home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / system / bios_asm.zip / BIOS.ASM next >
Assembly Source File  |  1988-01-18  |  179KB  |  3,798 lines

  1. Date:     Wed, 13 Jan 88 04:26 PST
  2. From:     <MULTI%TRIUMFCL.BITNET@CUNYVM.CUNY.EDU>
  3. Subject:  BIOS.ASM update INFO-IBMPC librarys
  4. To:       hicks@walker-emh.arpa
  5.  
  6. Page    80,132
  7. Title   BIOS    - For Intel 8088 or NEC "V20" turbo motherboards.  Use MASM 4.0
  8. ;
  9. ; This bios will work on IBM-PC/xt and many other compatibles that share a
  10. ; similar design concept.  You do not need to have a turbo motherboard to
  11. ; use this bios, but if you do, then use the following key sequence
  12. ;                               CTRL ALT -
  13. ; to toggle the computer speed between fast and slow (=IBM compatible)
  14. ;
  15. ; This BIOS can produce the following error messages at IPL time
  16. ;
  17. ER_BIOS equ     01h             ; Bad ROM bios checksum, patch last byte
  18. ER_RAM  equ     02h             ; Bad RAM in main memory, replace
  19. ER_CRT  equ     04h             ; Bad RAM in video card, replace
  20. ER_MEM  equ     10h             ; Bad RAM in vector area, replace
  21. ER_ROM  equ     20h             ; Bad ROM in expansion area, bad checksum
  22. ;
  23. ; The last two bytes have to be patched with DEBUG as follows
  24. ;
  25. ;   FFFF 00.xx          ( avoid ER_BIOS on bootstrap ) --------------------
  26. ;   FFFE 00.FE          ( leaves IBM-PC/xt signature ) -----------------  |
  27. ;                                                                      |  |
  28. ; where "xx" results in a zero checksum for the whole BIOS rom, for ex |  |
  29. ;                                                                      |  |
  30. ;               masm BIOS;              ( Assemble BIOS source code)   |  |
  31. ;               link BIOS;              ( Link the BIOS object code)   |  |
  32. ;               debug BIOS.EXE          ( Exe2bin  BIOS binary code)   |  |
  33. ;               -nBIOS.BIN              ( Name of the output binary)   |  |
  34. ;               -eCS:FFFE               ( Opens BIOS signature byte)   |  |
  35. ;               .FE                     ( Leave IBM-PC/xt signature) <--  |
  36. ;               -eCS:FFFF               ( Opens BIOS checksum  byte)      |
  37. ;;  ------->    .DC                     ( Force ROM checksum = zero) <-----
  38. ;;              -rBX                    ( Opens hi order byte count)
  39. ;;              :0                      (  ... must be 0 bytes long)
  40. ;;              -rCX                    ( Opens lo order byte count)
  41. ;;              :2000                   (  ... BIOS 2000 bytes long)
  42. ;;              -wCS:E000               ( Output to BIOS.BIN   file)
  43. ;;              -q
  44. ;;
  45. ;; You must correct the checksum by manually patching the last byte so as the
  46. ;; the entire 2764-2 eprom sums to zero.  I wish DEBUG could checksum blocks.
  47. ;
  48. ; ************************Miscellaneous definitions************************
  49. ;                                                                         *
  50. MAX_MEMORY      =704            ; Maximum kilobytes of memory allowed     *
  51. ;SLOW_FLOPPY    =1              ; Define to run floppy always at 4.77 mHz *
  52. ;                                                                         *
  53. ; ************************Miscellaneous definitions************************
  54. ;
  55. entry   macro   x
  56.         pad     =BANNER - $ + x - 0E000h
  57.         if pad LT 0
  58.         .err
  59.         %out    'No room for ENTRY point'
  60.         endif
  61.         if pad GT 0
  62.         db      pad DUP(0FFh)
  63.         endif
  64. endm
  65. ;
  66. jmpf    macro   x,y
  67.         db      0EAh;
  68.         dw      y,x
  69. endm
  70. ;
  71. retf    macro   x
  72.         ifb     <x>
  73.         db      0CBh
  74. else
  75.         db      0CAh
  76.         dw      x
  77. endif
  78. endm
  79. ;
  80. LF      equ     0Ah
  81. CR      equ     0Dh
  82. ;
  83.  .SALL                                          ; Suppress Macro Expansions
  84.  .LFCOND                                        ; List  False  Conditionals
  85. ;
  86. ASSUME  DS:code, SS:code, CS:code, ES:code
  87. data    SEGMENT at 40h                          ; IBM compatible data structure
  88.         dw      4 dup(?)        ; 40:00         ; RS232 com. ports - up to four
  89.         dw      4 dup(?)        ; 40:08         ; Printer ports    - up to four
  90.         dw      ?               ; 40:10         ; Equipment present word
  91.                                                 ;  + (1 iff floppies) *     1.
  92.                                                 ;  + (# 64K sys ram ) *     4.
  93.                                                 ;  + (init crt mode ) *    16.
  94.                                                 ;  + (# of floppies ) *    64.
  95.                                                 ;  + (# serial ports) *   512.
  96.                                                 ;  + (1 iff toy port) *  4096.
  97.                                                 ;  + (# parallel LPT) * 16384.
  98.         db      ?               ; 40:12         ; MFG test flags, unused by us
  99.         dw      ?               ; 40:13         ; Memory size, kilobytes
  100.         db      ?               ; 40:15         ; IPL errors<-table/scratchpad
  101.         db      ?                               ;  ...unused
  102. ;---------------[Keyboard data area]------------;
  103.         db      ?,?             ; 40:17         ; Shift/Alt/etc. keyboard flags
  104.         db      ?               ; 40:19         ; Alt-KEYPAD char. goes here
  105.         dw      ?               ; 40:1A         ;  --> keyboard buffer head
  106.         dw      ?               ; 40:1C         ;  --> keyboard buffer tail
  107.         dw      16 dup(?)       ; 40:1E         ; Keyboard Buffer (Scan,Value)
  108. ;---------------[Diskette data area]------------;
  109.         db      ?               ; 40:3E         ; Drive Calibration bits 0 - 3
  110.         db      ?               ; 40:3F         ; Drive Motor(s) on 0-3,7=write
  111.         db      ?               ; 40:40         ; Ticks (18/sec) til motor off
  112.         db      ?               ; 40:41         ; Floppy return code stat byte
  113.                                                 ;  1 = bad ic 765 command req.
  114.                                                 ;  2 = address mark not found
  115.                                                 ;  3 = write to protected disk
  116.                                                 ;  4 = sector not found
  117.                                                 ;  8 = data late (DMA overrun)
  118.                                                 ;  9 = DMA failed 64K page end
  119.                                                 ; 16 = bad CRC on floppy read
  120.                                                 ; 32 = bad NEC 765 controller
  121.                                                 ; 64 = seek operation failed
  122.                                                 ;128 = disk drive timed out
  123.         db      7 dup(?)        ; 40:42         ; Status bytes from NEC 765
  124. ;---------------[Video display area]------------;
  125.         db      ?               ; 40:49         ; Current CRT mode  (software)
  126.                                                 ;  0 = 40 x 25 text (no color)
  127.                                                 ;  1 = 40 x 25 text (16 color)
  128.                                                 ;  2 = 80 x 25 text (no color)
  129.                                                 ;  3 = 80 x 25 text (16 color)
  130.                                                 ;  4 = 320 x 200 grafix 4 color
  131.                                                 ;  5 = 320 x 200 grafix 0 color
  132.                                                 ;  6 = 640 x 200 grafix 0 color
  133.                                                 ;  7 = 80 x 25 text (mono card)
  134.         dw      ?               ; 40:4A         ; Columns on CRT screen
  135.         dw      ?               ; 40:4C         ; Bytes in the regen region
  136.         dw      ?               ; 40:4E         ; Byte offset in regen region
  137.         dw      8 dup(?)        ; 40:50         ; Cursor pos for up to 8 pages
  138.         dw      ?               ; 40:60         ; Current cursor mode setting
  139.         db      ?               ; 40:62         ; Current page on display
  140.         dw      ?               ; 40:63         ; Base addres (B000h or B800h)
  141.         db      ?               ; 40:65         ; ic 6845 mode reg. (hardware)
  142.         db      ?               ; 40:66         ; Current CGA palette
  143. ;---------------[Used to setup ROM]-------------;
  144.         dw      ?,?             ; 40:67         ; Eprom base Offset,Segment
  145.         db      ?               ; 40:6B         ; Last spurious interrupt IRQ
  146. ;---------------[Timer data area]---------------;
  147.         dw      ?               ; 40:6C         ; Ticks since midnite (lo)
  148.         dw      ?               ; 40:6E         ; Ticks since midnite (hi)
  149.         db      ?               ; 40:70         ; Non-zero if new day
  150. ;---------------[System data area]--------------;
  151.         db      ?               ; 40:71         ; Sign bit set iff break
  152.         dw      ?               ; 40:72         ; Warm boot iff 1234h value
  153. ;---------------[Hard disk scratchpad]----------;
  154.         dw      ?,?             ; 40:74         ;
  155. ;---------------[Timout areas/PRT/LPT]----------;
  156.         db      4 dup(?)        ; 40:78         ; Ticks for LPT 1-4 timeouts
  157.         db      4 dup(?)        ; 40:7C         ; Ticks for COM 1-4 timeouts
  158. ;---------------[Keyboard buf start/nd]---------;
  159.         dw      ?               ; 40:80         ; Contains 1Eh, buffer start
  160.         dw      ?               ; 40:82         ; Contains 3Eh, buffer end
  161. data    ENDS
  162.  
  163. dosdir  SEGMENT at 50h                          ; Boot disk directory from IPL
  164. xerox   label   byte                            ;  0 if Print Screen idle
  165.                                                 ;  1 if PrtSc xeroxing screen
  166.                                                 ;255 if PrtSc error in xerox
  167.                                                 ;  ...non-grafix PrtSc in bios
  168.         db      200h dup(?)                     ; PC-DOS bootstrap procedure
  169.                                                 ;  ...IBMBIO.COM buffers the
  170.                                                 ;  ...directory of the boot
  171.                                                 ;  ...device here at IPL time
  172.                                                 ;  ...when locating the guts
  173.                                                 ;  ...of the operating system
  174.                                                 ;  ...filename "IBMDOS.COM"
  175. dosdir  ends
  176.  
  177. dosseg  SEGMENT at 70h                          ; "Kernel" of PC-DOS op sys
  178. ;IBMBIO.COM file loaded by boot block. Device Drivers/Bootstrap. CONTIGUOUS<---
  179. ;IBMDOS.COM operating system nucleus immediately follows IBMBIO.COM and       |
  180. ;     doesn`t have to be contiguous.  The IBMDOS operating system nucleus     |
  181. ;     binary image is loaded by transient code in IBMBIO binary image         |
  182. dosseg  ends                                    ;                             |
  183. iplseg  SEGMENT at 0h                           ; Segment for boot block      |
  184. ;The following boot block is loaded with 512. bytes on the first sector of    |
  185. ;the bootable device by code resident in the ROM-resident bios.  Control is   |
  186. ;then transferred to the first word 0000:7C00 of the disk-resident bootstrap  |
  187.         ORG     07C00h                          ;  ..offset for boot block    |
  188. boot    db      200h dup(?)                     ;  ..start disk resident boot--
  189. iplseg  ends
  190.  
  191. code    SEGMENT
  192.         ORG     0E000h
  193.  
  194. BANNER  db      '  Generic Turbo XT Bios 1987',CR,LF
  195.         db      '      for 8088 or V20 cpu',CR,LF
  196.         db      '         (c)Anonymous',CR,LF
  197.         db      LF,0
  198.  
  199. LPTRS   dw      03BCh,0378h,0278h               ; Possible line printer ports
  200.  
  201.         ENTRY   0E05Bh                          ; IBM restart entry point
  202.  
  203. COLD:   MOV     AX,40h                          ; Entered by POWER_ON/RESET
  204.         MOV     DS,AX
  205.         MOV     Word ptr DS:72h,0               ; Show data areas not init
  206.  
  207. WARM:   CLI                                     ; Begin FLAG test of CPU
  208.         XOR     AX,AX
  209.         JB      HALT
  210.         JO      HALT
  211.         JS      HALT
  212.         JNZ     HALT
  213.         JPO     HALT
  214.         ADD     AX,1
  215.         JZ      HALT
  216.         JPE     HALT
  217.         SUB     AX,8002h
  218.         JS      HALT
  219.         INC     AX
  220.         JNO     HALT
  221.         SHL     AX,1
  222.         JNB     HALT
  223.         JNZ     HALT
  224.         SHL     AX,1
  225.         JB      HALT
  226.  
  227.         MOV     BX,0101010101010101b            ; Begin REGISTER test of CPU
  228. CPUTST: MOV     BP,BX
  229.         MOV     CX,BP
  230.         MOV     SP,CX
  231.         MOV     DX,SP
  232.         MOV     SS,DX
  233.         MOV     SI,SS
  234.         MOV     ES,SI
  235.         MOV     DI,ES
  236.         MOV     DS,DI
  237.         MOV     AX,DS
  238.         CMP     AX,0101010101010101b
  239.         JNZ     CPU1
  240.         NOT     AX
  241.         MOV     BX,AX
  242.         JMP     CPUTST
  243.  
  244. CPU1:   XOR     AX,1010101010101010b
  245.         JZ      CPU_OK
  246.  
  247. HALT:   HLT
  248.  
  249. CPU_OK: CLD
  250.         MOV     AL,0                            ; Prepare to initialize
  251.         OUT     0A0h,AL                         ;  ...no NMI interrupts
  252.         MOV     DX,3D8h                         ; Load Color Graphic port
  253.         OUT     DX,AL                           ;  ...no video display
  254.         MOV     DX,3B8h                         ; Load Monochrome port
  255.         INC     AL                              ;  ...no video display
  256.         OUT     DX,AL                           ;  ...write it out
  257.         MOV     AL,10011001b                    ; Program 8255 PIA chip
  258.         OUT     63h,AL                          ;  ...Ports A & C, inputs
  259.         MOV     AL,10100101b                    ; Set (non)turbo mode
  260.         OUT     61h,AL                          ;  ...on main board
  261.  
  262.         MOV     AL,01010100b                    ; ic 8253 inits memory refresh
  263.         OUT     43h,AL                          ;  ...chan 1 pulses ic 8237 to
  264.         MOV     AL,12h                          ;  ...dma every 12h clock ticks
  265.         OUT     41h,AL                          ;  ...64K done in 1 millisecond
  266.         MOV     AL,01000000b                    ; Latch value 12h in 8253 clock
  267.         OUT     43h,AL                          ;  ...chip channel 1 counter
  268.  
  269. IC8237: MOV     AL,0                            ; Do some initialization
  270.         OUT     81h,AL                          ;  ...dma page reg, chan 2
  271.         OUT     82h,AL                          ;  ...dma page reg, chan 3
  272.         OUT     83h,AL                          ;  ...dma page reg, chan 0,1
  273.         OUT     0Dh,AL                          ; Stop DMA on 8237 chip
  274.         MOV     AL,01011000b                    ; Refresh auto-init dummy read
  275.         OUT     0Bh,AL                          ;   ...on channel 0 of DMA chip
  276.         MOV     AL,01000001b                    ; Block verify
  277.         OUT     0Bh,AL                          ;   ...on channel 1 of DMA chip
  278.         MOV     AL,01000010b                    ; Block verify
  279.         OUT     0Bh,AL                          ;   ...on channel 2 of DMA chip
  280.         MOV     AL,01000011b                    ; Block verify
  281.         OUT     0Bh,AL                          ;   ...on channel 3 of DMA chip
  282.         MOV     AL,0FFh                         ; Refresh byte count
  283.         OUT     1,AL                            ;   ...send lo order
  284.         OUT     1,AL                            ;   ...send hi order
  285.         MOV     AL,0                            ; Initialize 8237 command reg
  286.         OUT     8,AL                            ;   ...with zero
  287.         OUT     0Ah,AL                          ; Enable DMA on all channels
  288.         MOV     AL,00110110b                    ; Set up 8253 timer chip
  289.         OUT     43h,AL                          ;   ...chan 0 is time of day
  290.         MOV     AL,0                            ; Request a divide by
  291.         OUT     40h,AL                          ;   ...65536 decimal
  292.         OUT     40h,AL                          ;   ...0000h or 18.2 tick/sec
  293.         MOV     DX,213h                         ; Expansion unit port
  294.         MOV     AL,1                            ;  ...enable it
  295.         OUT     DX,AL                           ;  ...do the enable
  296.         MOV     AX,40h                          ; Get bios impure segment
  297.         MOV     DS,AX                           ;  ...into DS register
  298.         MOV     SI,DS:72h                       ; Save reset flag in SI reg
  299.         XOR     AX,AX                           ;  ...cause memory check
  300.         MOV     BP,AX                           ;  ...will clobber the flag
  301.         MOV     BX,AX                           ; Start at segment 0000h
  302.         MOV     DX,55AAh                        ;  ...get pattern
  303.         CLD                                     ; Strings auto-increment
  304.  
  305. MEMSIZ: XOR     DI,DI                           ; Location XXXX:0
  306.         MOV     ES,BX                           ;  ...load segment
  307.         MOV     ES:[DI],DX                      ;  ...write pattern
  308.         CMP     DX,ES:[DI]                      ;  ...compare
  309.         JNZ     MEM_ND                          ;  ...failed, memory end
  310.         MOV     CX,2000h                        ; Else zero 16 kilobytes
  311.         REPZ    STOSW                           ;  ...with instruction
  312.         ADD     BH,4                            ;  ...get next 16K bytes
  313. ifdef   MAX_MEMORY
  314.         CMP     BH,MAX_MEMORY SHR 2             ; Found max legal user ram?
  315. else
  316.         CMP     BH,0A0h                         ; Found max legal IBM ram?
  317. endif
  318.         JNZ     MEMSIZ                          ;  ...no, then check more
  319.  
  320. MEM_ND: MOV     DS:72h,SI                       ; Save pointer
  321.         XOR     AX,AX
  322.         MOV     ES,AX                           ; ES = vector segment
  323.         MOV     AX,80h
  324.         MOV     SS,AX                           ; Set up temporary stack at
  325.         MOV     SP,100h                         ;  0080:0100 for memory check
  326.         PUSH    BP
  327.         PUSH    BX
  328.         MOV     BP,2
  329.         CALL    MEMTST                          ; Memory check ES:0 - ES:0400
  330.         POP     AX
  331.         MOV     CL,6
  332.         SHR     AX,CL
  333.         MOV     DS:13h,AX
  334.         POP     AX
  335.         JNB     MEM_01
  336.         OR      AL,ER_MEM                       ; Show vector area bad
  337.  
  338. MEM_01: MOV     DS:15h,AL                       ; Save IPL error code
  339.         XOR     AX,AX
  340.         PUSH    AX
  341.         PUSH    AX
  342.         PUSH    AX
  343.         PUSH    AX
  344.         PUSH    AX
  345.         MOV     AX,30h                          ; Set up IBM-compatible stack
  346.         MOV     SS,AX                           ;  ...segment 0030h
  347.         MOV     SP,100h                         ;  ...offset  0100h
  348.         PUSH    DS
  349.         MOV     BX,0E000h                       ; Check BIOS eprom
  350.         PUSH    CS
  351.         POP     DS                              ;  ...at F000:E000
  352.         MOV     AH,1
  353.         CALL    CHKSUM                          ;  ...for valid checksum
  354.         POP     DS                              ;  ...restore impure<-DS
  355.         JZ      IC8259
  356.         OR      Byte ptr DS:15h,ER_BIOS         ; Checksum error BIOS eprom
  357.  
  358. IC8259: CLI                                     ; Init interrupt controller
  359.         MOV     AL,13h
  360.         OUT     20h,AL
  361.         MOV     AL,8
  362.         OUT     21h,AL
  363.         MOV     AL,9
  364.         OUT     21h,AL
  365.         MOV     AL,0FFh
  366.         OUT     21h,AL
  367.         PUSH    DS
  368.         XOR     AX,AX                           ; 8 nonsense vectors begin table
  369.         MOV     ES,AX                           ;  ...at segment 0000h
  370.         PUSH    CS
  371.         POP     DS
  372.         MOV     CX,8                            ; Vectors 00h - 07h unused
  373.         XOR     DI,DI                           ;  ...we start at vec 00h
  374.  
  375. LO_VEC: MOV     AX,offset IGNORE                ; Nonsense interrupt from RSX
  376.         STOSW
  377.         MOV     AX,CS                           ;  ...bios ROM segment
  378.         STOSW
  379.         LOOP    LO_VEC
  380.  
  381.         MOV     SI,offset VECTORS               ; SI --> Vector address table
  382.         MOV     CX,18h                          ;  ... vectors 08h - 1Fh busy
  383.  
  384. HI_VEC: MOVSW                                   ; Get INTERRUPT bios ROM offset
  385.         MOV     AX,CS
  386.         STOSW                                   ;  ...INTERRUPT bios ROM segment
  387.         LOOP    HI_VEC
  388.  
  389.         MOV     AX,0F600h                       ; AX --> Rom basic segment
  390.         MOV     DS,AX                           ; DS -->  "    "     "
  391.         XOR     BX,BX                           ; BX  =  Rom basic offset
  392.         MOV     AH,4                            ; Four basic roms to check
  393.  
  394.         MOV     BP,SP                           ; Save the stack pointer
  395.         PUSH    CS                              ;  ...push code segment
  396.         MOV     DX,offset SKIP                  ; Save the code offset
  397.         PUSH    DX                              ;  ...for RAM_PATCH subroutine
  398.         MOV     DX,0EA90h                       ; Mov DX,'NOP,JMP_FAR'
  399.         PUSH    DX                              ;  ...save it on stack
  400.         MOV     DX,0178Bh                       ; Mov DX,'MOV DX,[BX]'
  401.         PUSH    DX                              ;  ...save it on stack
  402.         PUSH    SS                              ; Save stack segment
  403.         MOV     DX,SP                           ;  ...get the stack offset
  404.         ADD     DX,02h                          ;  ...calculate xfer addr.
  405.         PUSH    DX                              ;  ...save it on the stack
  406. ;
  407.         RETF                                    ; Test for BASIC rom
  408. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  409. ;       MOV     DX,[BX]                         ; Executes off the stack ;
  410. ;       JMPF    0F000h,SKIP                     ;       ...in RAM space  ;
  411. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  412. SKIP:   MOV     SP,BP                           ; Restore the stack pointer
  413.         CMP     DL,DH                           ;  ...compare 1st and 2nd byte
  414.         JE      kosher                          ;  ...perfection.  No piracy
  415.  
  416. B_ROM:  CALL    CHKSUM                          ; Scan for BASIC roms
  417.         JNZ     kosher                          ;  ...bad basic rom
  418.         DEC     AH                              ; Continue
  419.         JNZ     B_ROM                           ;  ...yes, more
  420.  
  421.         POP     DS                              ; Else valid  basic
  422.         MOV     DI,60h                          ;  ...install basic
  423.  
  424.         XOR     AX,AX                           ;  ...zero  BASIC interrupt
  425.         STOSW                                   ;  ...offset
  426.         MOV     AX,0F600h                       ;  ...F600h BASIC interrupt
  427.         STOSW                                   ;  ...segment
  428.  
  429.         PUSH    DS
  430. kosher: POP     DS                              ; Setup special low vectors
  431.         MOV     Word ptr ES:8,offset int_2      ;  ...NMI interrupt
  432.         MOV     Word ptr ES:14h,offset int_5    ;  ...print screen interrupt
  433.         MOV     Word ptr ES:7Ch,0               ; No special graphics chars.
  434.         MOV     Word ptr ES:7Eh,0               ;  ...so zero vector 1Fh
  435.         MOV     DX,61h
  436.         IN      AL,DX                           ; Read machine flags
  437.         OR      AL,00110000b                    ;  ...clear old parity error
  438.         OUT     DX,AL                           ; Write them back to reset
  439.         AND     AL,11001111b                    ;  ...enable parity
  440.         OUT     DX,AL                           ; Write back, parity enabled
  441.         MOV     AL,80h                          ;  ...allow NMI interrupts
  442.         OUT     0A0h,AL
  443.         MOV     AX,0000000000110000b            ; Assume monochrome video
  444.         MOV     DS:10h,AX                       ;  ...card has been installed
  445.         INT     10h                             ;  ...initialize if present
  446.         MOV     AX,0000000000100000b            ; Assume color/graphics video
  447.         MOV     DS:10h,AX                       ;  ...card has been installed
  448.         INT     10h                             ;  ...initialize if present
  449.         IN      AL,62h                          ; Get memory size (64K bytes)
  450.         AND     AL,00001111b                    ;  ...in bits 2,3 lo nibble
  451.         MOV     AH,AL                           ; Save memory size nibble
  452.         MOV     AL,10101101b
  453.         OUT     61h,AL
  454.         IN      AL,62h                          ; Get no. of floppies (0-3)
  455.         MOV     CL,4                            ;  ...and init. video mode
  456.         SHL     AL,CL                           ;  ...shift in hi nibble
  457.         OR      AL,AH
  458.         MOV     AH,0
  459.         MOV     DS:10h,AX                       ; Start building Equipment Flag
  460.         AND     AL,00110000b                    ;  ...if video card, mode set
  461.         JNZ     LE232                           ;  ...found video interface
  462.         MOV     AX,offset DUMMY                 ; No hardware, DUMMY: becomes
  463.         MOV     ES:40h,AX                       ;  ...INT_10 video service
  464.         JMP     short   LE235
  465.  
  466. LE232:  CALL    V_INIT                          ; Setup video
  467.  
  468. LE235:  MOV     AL,00001000b                    ; Read low switches
  469.         OUT     61h,AL
  470.         MOV     CX,2956h
  471.  
  472. WAIT_1: LOOP    WAIT_1
  473.         MOV     AL,11001000b                    ; Keyboard acknowledge
  474.         OUT     61h,AL                          ;  ...send the request
  475.         XOR     AL,10000000b                    ; Toggle to enable
  476.         OUT     61h,AL                          ;  ...send key enable
  477.         MOV     AX,1Eh                          ; Offset to buffer start
  478.         MOV     DS:1Ah,AX                       ; Buffer head pointer
  479.         MOV     DS:1Ch,AX                       ; Buffer tail pointer
  480.         MOV     DS:80h,AX                       ; Buffer start
  481.         ADD     AX,20h                          ;  ...size
  482.         MOV     DS:82h,AX                       ; Buffer end
  483.         JMP     short   V_CONT
  484.  
  485. FAO:    MOV     DL,AL                           ; Formatted ascii output
  486.  
  487. FAO_1:  MOV     AX,BX                           ; Get position for
  488.         CALL    LOCATE                          ;  ...cursor routine
  489.         PUSH    SI                              ; Get string address
  490.         CALL    PRINT                           ;  ...print string
  491.         MOV     AX,ES:[BP+0]                    ; Get port # to print
  492.         CALL    BIGNUM                          ;  ...four digits
  493.         POP     SI                              ; Restore string address
  494.         INC     BP                              ;  ...Address of port
  495.         INC     BP                              ;  ...is two bytes long
  496.         INC     BH                              ;  ...down one line
  497.         DEC     DL                              ; Decrement device count
  498.         JNZ     FAO_1                           ; ...back for more
  499.         RET
  500.  
  501. K_BYTE: CLC                                     ; Say no error
  502.         MOV     AL,DL                           ;  ...size "checked"
  503.         INC     AL                              ;  ...show more
  504.         DAA
  505.         MOV     DL,AL
  506.         JNB     KBY_01
  507.         MOV     AL,DH                           ;  ...do carry
  508.         ADC     AL,0
  509.         DAA
  510.         MOV     DH,AL
  511.  
  512. KBY_01: MOV     AL,DH
  513.         CALL    DIGIT                           ; Print hex digit
  514.         MOV     AL,DL
  515.         MOV     CL,4
  516.         ROR     AL,CL
  517.         CALL    DIGIT                           ; Print hex digit
  518.         MOV     AL,DL
  519.         CALL    DIGIT                           ; Print hex digit
  520.         RET
  521.  
  522. TIMER:  MOV     DX,241h                         ; Check for timer #2 port
  523.         CLI
  524.         IN      AL,DX                           ;  ..read BCD seconds/100
  525.         STI
  526.         CMP     AL,99h                          ; Are BCD digits in range?
  527.         JBE     SER_01                          ;  ...yes, port exists
  528. ;
  529.         MOV     DX,341h                         ; Check for timer #1 port
  530.         CLI
  531.         IN      AL,DX                           ;  ..read BCD seconds/100
  532.         STI
  533.         CMP     AL,99h                          ; Are BCD digits in range?
  534.         JBE     SER_01                          ;  ...yes, port exists
  535. ;
  536.         STC                                     ; No hardware, ports 0FFh
  537.         RET
  538.  
  539. SER_01: CLC                                     ; Found timer(s) answering
  540.         RET
  541.  
  542. V_CONT: MOV     BP,4                            ; Assume monochrome, 4K memory
  543.         MOV     BX,0B000h                       ;  ...segment in BX
  544.         MOV     AL,DS:49h                       ; Get the video mode
  545.         CMP     AL,7                            ;  ...was it mono?
  546.         JZ      M_SEG                           ;  ...yes, skip
  547.         MOV     BP,10h                          ; Else CGA, has 16K memory
  548.         MOV     BX,0B800h                       ;  ...segment in BX
  549.  
  550. M_SEG:  PUSH    BX                              ; Load video seg in ES
  551.         POP     ES
  552.         MOV     AL,DS:65h                       ; Get CRT hardware mode
  553.         AND     AL,11110111b                    ;  ...disable video
  554.         MOV     DX,DS:63h                       ; Get 6845 index port
  555.         ADD     DX,4                            ;  ...add offset for
  556.         OUT     DX,AL                           ; 6845 controller port
  557.  
  558. CRTRAM: CALL    MEMTST                          ; Memory check ES:0 - ES:0400
  559.         DEC     BP
  560.         JNZ     CRTRAM                          ; Loop until CRT RAM checked
  561.         JNB     LE2F5
  562.         OR      Byte ptr DS:15h,ER_CRT          ; Set CRT RAM error in status
  563.  
  564. LE2F5:  CALL    V_INIT
  565.         MOV     AX,1414h                        ; Time-out value seconds
  566.         MOV     DS:78h,AX                       ;  ...LPT1
  567.         MOV     DS:7Ah,AX                       ;  ...LPT2
  568.         MOV     AX,101h                         ; Time-out value seconds
  569.         MOV     DS:7Ch,AX                       ;  ...COM1
  570.         MOV     DS:7Eh,AX                       ;  ...COM2
  571.         MOV     SI,offset LPTRS                 ; SI --> LPTR port table
  572.         XOR     DI,DI                           ;  ...offset into data seg
  573.         MOV     CX,3                            ;  ...number of printers
  574.  
  575. NXTPRT: MOV     DX,CS:[SI]                      ; Get LPTR port
  576.         MOV     AL,10101010b                    ;  ...write value
  577.         OUT     DX,AL                           ;  ...to the LPTR
  578.         MOV     AL,11111111b                    ; Dummy data value
  579.         OUT     0C0h,AL                         ;  ...on the bus
  580.         IN      AL,DX                           ; Read code back
  581.         CMP     AL,10101010b                    ;  ...check code
  582.         JNZ     NO_LPT                          ;  ...no printer found
  583.         MOV     [DI+8],DX                       ; Save printer port
  584.         INC     DI
  585.         INC     DI
  586.  
  587. NO_LPT: INC     SI
  588.         INC     SI
  589.         LOOP    NXTPRT
  590.         MOV     AX,DI                           ; Number of printers * 2
  591.         MOV     CL,3                            ;  ...get shift count
  592.         ROR     AL,CL                           ;  ...divide by eight
  593.         MOV     DS:11h,AL                       ;  ...save in equip. flag
  594.  
  595.         XOR     DI,DI                           ; com port(s) at 40:00 (hex)
  596.  
  597. COM_1:  MOV     DX,3FBh                         ; COM #1 line control reg.
  598.         MOV     AL,00011010b                    ;  ...7 bits, even parity
  599.         OUT     DX,AL                           ; Reset COM #1 line cont. reg
  600.         MOV     AL,11111111b                    ;  ...noise pattern
  601.         OUT     0C0h,AL                         ; Write pattern on data buss
  602.         IN      AL,DX                           ;  ...read result from COM #1
  603.         CMP     AL,00011010b                    ; Check if serial port exists
  604.         JNZ     COM_2                           ;  ...skip if no COM #1 port
  605.         MOV     Word ptr [DI],3F8h              ; Else save port # in impure
  606.         INC     DI                              ;  ...potential COM #2 port
  607.         INC     DI                              ;  ...is at 40:02 (hex)
  608.  
  609. COM_2:  MOV     DX,2FBh                         ; COM #2 line control reg
  610.         MOV     AL,00011010b                    ;  ...7 bits, even parity
  611.         OUT     DX,AL                           ; Reset COM #2 line cont. reg
  612.         MOV     AL,11111111b                    ;  ...noise pattern
  613.         OUT     0C0h,AL                         ; Write pattern on data buss
  614.         IN      AL,DX                           ;  ...read results from COM #2
  615.         CMP     AL,00011010b                    ; Check if serial port exists
  616.         JNZ     COM_CT                          ;  ...skip if no COM #2 port
  617.         MOV     word ptr [DI],2F8h              ; Else save port # in impure
  618.         INC     DI                              ;  ...total number of serial
  619.         INC     DI                              ;  ...interfaces times two
  620.  
  621. COM_CT: MOV     AX,DI                           ; Get serial interface count
  622.         OR      DS:11h,AL                       ;  ...equip.  flag
  623.         MOV     DX,201h
  624.         IN      AL,DX                           ; Read game controller
  625.         TEST    AL,0Fh                          ;  ...anything there?
  626.         JNZ     NOGAME                          ;  ...yes, invalid
  627.         OR      Byte ptr DS:11h,00010000b       ; Else game port present
  628.  
  629. NOGAME: MOV     DX,0C000h                       ; ROM segment start
  630.         PUSH    DS
  631.  
  632. FNDROM: MOV     DS,DX                           ; Load ROM segment
  633.         XOR     BX,BX                           ;  ...ID offset
  634.         MOV     AX,[BX]                         ; Read the ROM id
  635.         CMP     AX,0AA55h
  636.         JNZ     NXTROM                          ;  ...not valid ROM
  637.         MOV     AX,40h
  638.         MOV     ES,AX
  639.         MOV     AH,0
  640.         MOV     AL,[BX+2]                       ; Get ROM size (bytes * 512)
  641.         MOV     CL,5
  642.         SHL     AX,CL                           ; Now ROM size in segments
  643.         ADD     DX,AX                           ;  ...add base segment
  644.         MOV     CL,4
  645.         SHL     AX,CL                           ; ROM address in bytes
  646.         MOV     CX,AX                           ;  ...checksum requires CX
  647.         CALL    CHK_01                          ; Find ROM checksum
  648.         JNZ     BADROM                          ;  ...bad ROM
  649.         PUSH    DX
  650.         MOV     Word ptr ES:67h,3               ; Offset  for ROM being setup
  651.         MOV     ES:69h,DS                       ; Segment for ROM being setup
  652.         CALL    Dword ptr ES:67h                ;  ...call ROM initialization
  653.         POP     DX
  654.         JMP     short   FND_01
  655.  
  656. BADROM: OR      Byte ptr ES:15h,ER_ROM          ; ROM present, bad checksum
  657.  
  658. NXTROM: ADD     DX,80h                          ; Segment for next ROM
  659.  
  660. FND_01: CMP     DX,0F600h                       ; End of ROM space
  661.         JL      FNDROM                          ;  ...no, continue
  662.         POP     DS
  663.         IN      AL,21h                          ; Read ic 8259 interrupt mask
  664.         AND     AL,10111100b                    ;  ...enable IRQ (0,1,6) ints
  665.         OUT     21h,AL                          ; (tod_clock,key,floppy_disk)
  666.  
  667.         MOV     AH,1
  668.         MOV     CH,0F0h
  669.         INT     10h                             ; Set cursor type
  670.         CALL    BLANK                           ;  ...clear display
  671.         PUSH    DS
  672.         PUSH    CS
  673.         POP     DS
  674.         POP     ES
  675.         TEST    Byte ptr ES:10h,1               ; Floppy disk present?
  676.         JZ      FND_02                          ;  ...no
  677.         CMP     Word ptr ES:72h,1234h           ; Bios setup before?
  678.         JNZ     CONFIG                          ;  ...no
  679. FND_02: JMP     RESET                           ; Else skip memory check
  680.  
  681. CONFIG: MOV     AX,41Ah                         ; Where to move cursor
  682.         MOV     SI,offset STUF                  ; ...equipment message
  683.         CALL    LOCATE                          ; ...position cursor
  684.         CALL    PRINT                           ; ...and print string
  685.         MOV     AX,51Bh                         ; New cursor position
  686.         MOV     SI,offset STUF_1                ;  ...CR/LF
  687.         CALL    Locate                          ;  ...position cursor
  688.         CALL    PRINT                           ;  ...and print string
  689.         TEST    Byte ptr ES:15h,11111111b       ; Any error so far?
  690.         JZ      VALID                           ;  ...no, skip
  691.         CALL    PRINT                           ; Print string
  692.         MOV     AL,ES:15h                       ;  ...get error number
  693.         CALL    NUMBER                          ;  ...print hex value
  694.         CALL    PRINT                           ;  ...print prompt
  695.         MOV     BL,4                            ;  ...long beep
  696.         CALL    BEEP
  697.         CALL    GETCH                           ; Wait for keypress
  698.         PUSH    AX                              ;  ...save answer
  699.         CALL    OUTCHR                          ;  ...echo answer
  700.         POP     AX                              ;  ...get  answer
  701.         CMP     AL,'Y'                          ; Was it "Y"
  702.         JZ      FND_02                          ;  ...ok, continue
  703.         CMP     AL,'y'                          ; Was it "y"
  704.         JZ      FND_02                          ;  ...ok, continue
  705.         JMPF    0F000h,COLD                     ; Else cold reset
  706.  
  707. VALID:  MOV     SI,offset STUF_2                ; No errors found, load banner
  708.         CALL    PRINT                           ;  ...and print string
  709.         MOV     AX,81Eh                         ; Where to move cursor
  710.         CALL    LOCATE                          ;  ...position cursor
  711.         CALL    PRINT                           ;  ...and print string
  712.         MOV     AX,91Ch                         ; Where to move cursor
  713.         CALL    LOCATE                          ;  ...position cursor
  714.         MOV     BL,17h                          ; Character count
  715.  
  716. FENCE:  MOV     AL,'-'                          ; Load ascii minus
  717.         CALL    OUTCHR                          ;  ...and print it
  718.         DEC     BL
  719.         JNZ     FENCE
  720.         MOV     AX,0A21h                        ; Where to move cursor
  721.         CALL    LOCATE                          ;  ...position cursor
  722.         MOV     AL,ES:49h                       ; Get CRT mode
  723.         CMP     AL,7
  724.         JZ      FEN_01                          ;  ...monochrome
  725.         MOV     SI,offset STUF_3                ;  ...color/graphics
  726.  
  727. FEN_01: CALL    PRINT                           ; Print the string
  728.         MOV     BX,0B21h
  729.         MOV     AL,ES:11h                       ; Get equipment byte
  730.         PUSH    AX
  731.         MOV     CL,6
  732.         ROR     AL,CL
  733.         AND     AL,3                            ; Number of printers
  734.         JZ      FEN_02
  735.         MOV     BP,8
  736.         MOV     SI,offset STUF_4
  737.         CALL    FAO                             ; Formatted ascii output
  738.  
  739. FEN_02: POP     AX                              ; Equipment byte restore
  740.         MOV     SI,offset STUF_5                ;  ...game controller
  741.         PUSH    AX                              ; Save a copy of equip. byte
  742.         TEST    AL,00010000b
  743.         JZ      NO_TOY                          ; Jump if no game controller
  744.         MOV     AX,BX
  745.         CALL    LOCATE                          ; Position cursor
  746.         CALL    PRINT                           ;  ...and print string
  747.         INC     BH                              ;  ...scroll line
  748.  
  749. NO_TOY: CALL    TIMER                           ; Timer devices?
  750.         JB      NO_TIM                          ;  ...skip if none
  751.         MOV     AX,BX
  752.         CALL    LOCATE                          ; Position cursor
  753.         INC     BH
  754.         MOV     SI,offset STUF_8
  755.         CALL    PRINT
  756.  
  757. NO_TIM: POP     AX
  758.         MOV     SI,offset STUF_6
  759.         ROR     AL,1                            ; Check for COM port
  760.         AND     AL,3
  761.         JZ      NO_COM                          ; ...skip if no com
  762.         XOR     BP,BP
  763.         CALL    FAO                             ; Formatted ascii output
  764.  
  765. NO_COM: MOV     AX,121Ch                        ; Where to position cursor
  766.         CALL    LOCATE                          ;  ...position cursor
  767.         MOV     SI,offset STUF_7                ; Memory size string
  768.         CALL    PRINT                           ;  ...print string
  769.         PUSH    ES
  770.         MOV     BP,ES:13h                       ; Memory size (1 K blocks)
  771.         DEC     BP
  772.         DEC     BP
  773.         MOV     SI,2
  774.         MOV     DX,SI
  775.         MOV     AX,80h
  776.         MOV     ES,AX
  777.  
  778. CUTE:   MOV     AX,122Bh                        ; Cursory check of memory
  779.         CALL    LOCATE                          ;  ...position cursor
  780.         CALL    K_BYTE                          ;  ...print size in K
  781.         CALL    MEMTST                          ; Memory check ES:0 - ES:0400
  782.         JB      BADRAM                          ;  ...bad RAM found  (How ???)
  783.         DEC     BP
  784.         JNZ     CUTE
  785.         POP     ES
  786.  
  787. RESET:  MOV     BL,2                            ; Do a warm boot
  788.         CALL    BEEP                            ; ...short beep
  789.         CALL    BLANK                           ; ...clear display
  790.         MOV     Word ptr ES:72h,1234h           ; Show cold start done
  791.         MOV     AH,1
  792.         MOV     CX,607h                         ; Set underline cursor
  793.         INT     10h
  794.         MOV     SI,offset BANNER                ; Load banner address
  795.         CALL    PRINT                           ; ...and print string
  796.         INT     19h                             ; Boot the machine
  797.  
  798. BADRAM: POP     ES
  799.         OR      Byte ptr ES:15h,ER_RAM          ; Show "Bad Ram" error
  800.         JMP     CONFIG
  801.  
  802. STUF    db      ' Generic Turbo XT Bios 1987',0
  803. STUF_1  db      CR,LF,0,'System error #',0,', Continue?',0
  804. STUF_2  db      ' ',0,'Interface card list',0,'Monochrome',0
  805. STUF_3  db      'Color/Graphics',0
  806. STUF_4  db      'Printer #',0
  807. STUF_5  db      'Game controller',0
  808. STUF_6  db      'Async. commu.  #',0
  809. STUF_7  db      'RAM Testing .. 000 KB',0
  810. STUF_8  db      'Timer',0
  811.  
  812.         ENTRY   0E600h                          ; Not necessary to IPL here..
  813.  
  814. IPL:    STI                                     ; Called to reboot computer
  815.         XOR     AX,AX
  816.         MOV     DS,AX
  817.         MOV     Word ptr DS:78h,offset INT_1E   ; Get disk parameter table
  818.         MOV     DS:7Ah,CS                       ;  ...save segment
  819.         MOV     AX,4                            ; Try up to four times
  820.  
  821. RETRY:  PUSH    AX                              ; Save retry count
  822.         MOV     AH,0                            ;  ...reset
  823.         INT     13h                             ;  ...floppy
  824.         JB      FAILED
  825.         MOV     AL,1                            ; One sector
  826.         MOV     AH,2                            ;  ...read
  827.         XOR     DX,DX                           ;  ...from drive 0, head 0
  828.         MOV     ES,DX                           ;  ...segment 0
  829.         MOV     BX,7C00h                        ;  ...offset  7C00
  830.         MOV     CL,1                            ;  ...sector 1
  831.         MOV     CH,0                            ;  ...track  0
  832.         INT     13h                             ;  ...floppy
  833.         JB      FAILED
  834.         JMPF    0000h,7C00h                     ; Call the boot block
  835. ;
  836. FAILED: POP     AX                              ; Get retries
  837.         DEC     AL                              ;  ...one less
  838.         JNZ     RETRY
  839.  
  840. NODISK: OR      AH,AH                           ; Disk present?
  841.         JNZ     DERROR                          ;  ...yes
  842.         CALL    BLANK                           ; Clear display
  843.         PUSH    CS
  844.         POP     DS
  845.         MOV     SI,offset DSKMSG                ; Load disk message
  846.         CALL    PRINT                           ;  ...and print string
  847.         CALL    GETCH                           ;  ...wait for keypress
  848.         CALL    BLANK                           ;  ...clear display
  849.         MOV     AX,0FF04h                       ; Reset retry count
  850.         JMP     RETRY                           ;  ...and retry
  851.  
  852. DERROR: XOR     AX,AX                           ; Error from NEC 765
  853.         MOV     DS,AX
  854.         LES     AX,Dword ptr DS:60h             ; ROM basic vector ES:AX
  855.         MOV     BX,ES                           ;  ...get ROM basic segment
  856.         CMP     AX,0
  857.         MOV     AX,0
  858.         JNZ     NODISK                          ; No ROM basic found
  859.         CMP     BX,0F600h
  860.         JNZ     NODISK                          ; Invalid ROM basic segment
  861.         INT     18h                             ;  ...else call ROM basic
  862.  
  863. DSKMSG  db      'Insert diskette in DRIVE A.',CR,LF
  864.         db      '    Press any key.',0
  865.  
  866.         ENTRY   0E6F2h                          ; IBM entry point for INT 19h
  867.  
  868. INT_19: JMP     IPL                             ; Warm boot
  869.  
  870.         ENTRY   0E729h                          ; IBM entry point for INT 14h
  871.  
  872. BAUD    dw      0417h                           ;  110 baud clock divisor
  873.         dw      0300h                           ;  150 baud clock divisor
  874.         dw      0180h                           ;  300 baud clock divisor
  875.         dw      00C0h                           ;  600 baud clock divisor
  876.         dw      0060h                           ; 1200 baud clock divisor
  877.         dw      0030h                           ; 2400 baud clock divisor
  878.         dw      0018h                           ; 4800 baud clock divisor
  879.         dw      000Ch                           ; 9600 baud clock divisor
  880.  
  881. INT_14: STI                                     ; Serial com. RS232 services
  882.         PUSH    DS                              ;  ...thru IC 8250 uart (ugh)
  883.         PUSH    DX                              ;  ...DX = COM device (0 - 3)
  884.         PUSH    SI
  885.         PUSH    DI
  886.         PUSH    CX
  887.         PUSH    BX
  888.         MOV     BX,40h
  889.         MOV     DS,BX
  890.         MOV     DI,DX                           ;
  891.         MOV     BX,DX                           ; RS232 serial COM index (0-3)
  892.         SHL     BX,1                            ;  ...index by bytes
  893.         MOV     DX,[BX]                         ; Convert index to port number
  894.         OR      DX,DX                           ;  ...by indexing 40:0
  895.         JZ      COM_ND                          ;  ...no such COM device, exit
  896.         OR      AH,AH                           ; Init on AH=0
  897.         JZ      COMINI
  898.         DEC     AH
  899.         JZ      COMSND                          ; Send on AH=1
  900.         DEC     AH
  901.         JZ      COMGET                          ; Rcvd on AH=2
  902.         DEC     AH
  903.         JZ      COMSTS                          ; Stat on AH=3
  904.  
  905. COM_ND: POP     BX                              ; End of COM service
  906.         POP     CX
  907.         POP     DI
  908.         POP     SI
  909.         POP     DX
  910.         POP     DS
  911.         IRET
  912.  
  913. COMINI: PUSH    AX                              ; Init COM port.  AL has data
  914.                                                 ; = (Word Length in Bits - 5)
  915.                                                 ;  +(1 iff two stop bits) *  4
  916.                                                 ;  +(1 iff parity enable) *  8
  917.                                                 ;  +(1 iff parity even  ) * 16
  918.                                                 ;  +(BAUD: select 0-7   ) * 32
  919.         MOV     BL,AL
  920.         ADD     DX,3                            ; Line Control Register (LCR)
  921.         MOV     AL,80h                          ;  ...index RS232_BASE + 3
  922.         OUT     DX,AL                           ; Tell LCR to set (latch) baud
  923.         MOV     CL,4
  924.         ROL     BL,CL                           ; Baud rate selects by words
  925.         AND     BX,00001110b                    ;  ...mask off extraneous
  926.         MOV     AX,Word ptr CS:[BX+BAUD]        ; Clock divisor in AX
  927.         SUB     DX,3                            ; Load in lo order baud rate
  928.         OUT     DX,AL                           ;  ...index RS232_BASE + 0
  929.         INC     DX                              ; Load in hi order baud rate
  930.         MOV     AL,AH
  931.         OUT     DX,AL                           ;  ...index RS232_BASE + 1
  932.         POP     AX
  933.         INC     DX                              ; Find Line Control Register
  934.         INC     DX                              ;  ...index RS232_BASE + 3
  935.         AND     AL,00011111b                    ; Mask out the baud rate
  936.         OUT     DX,AL                           ;  ...set (censored) init stat
  937.         MOV     AL,0
  938.         DEC     DX                              ; Interrupt Enable Reg. (IER)
  939.         DEC     DX                              ;  ...index RS232_BASE + 1
  940.         OUT     DX,AL                           ; Interrupt is disabled
  941.         DEC     DX
  942.         JMP     short   COMSTS                  ; Return current status
  943.  
  944. COMSND: PUSH    AX                              ; Send AL thru COM port
  945.         MOV     AL,3
  946.         MOV     BH,00110000b                    ;(Data Set Ready,Clear To Send)
  947.         MOV     BL,00100000b                    ;  ..(Data Terminal Ready) wait
  948.         CALL    WAITFR                          ; Wait for transmitter to idle
  949.         JNZ     HUNG                            ;  ...time-out error
  950.         SUB     DX,5                            ;  ...(xmit) index RS232_BASE
  951.         POP     CX                              ; Restore char to CL register
  952.         MOV     AL,CL                           ;  ...get copy to load in uart
  953.         OUT     DX,AL                           ;  ...transmit char to IC 8250
  954.         JMP     COM_ND                          ;  ...AH register has status
  955.  
  956. HUNG:   POP     CX                              ; Transmit error, restore char
  957.         MOV     AL,CL                           ;  ...in AL for compatibility
  958.                                                 ;  ...fall thru to gen. error
  959. HUNGG:  OR      AH,80h                          ; Set error (=sign) bit in AH
  960.         JMP     COM_ND                          ;  ...common exit
  961.  
  962. COMGET: MOV     AL,1                            ; Get char. from COM port
  963.         MOV     BH,00100000b                    ; Wait on DSR (Data Set  Ready)
  964.         MOV     BL,00000001b                    ; Wait on DTR (Data Term.Ready)
  965.         CALL    WAITFR                          ;  ...wait for character
  966.         JNZ     HUNGG                           ;  ...time-out error
  967.         AND     AH,00011110b                    ; Mask AH for error bits
  968.         SUB     DX,5                            ;  ...(rcvr) index RS232_BASE
  969.         IN      AL,DX                           ; Read the character
  970.         JMP     COM_ND                          ;  ...AH register has status
  971.  
  972. COMSTS: ADD     DX,5                            ; Calculate line control stat
  973.         IN      AL,DX                           ;  ...index RS232_BASE + 5
  974.         MOV     AH,AL                           ;  ...save high order status
  975.         INC     DX                              ; Calculate modem stat. reg.
  976.         IN      AL,DX                           ;  ...index RS232_BASE + 6
  977.         JMP     COM_ND                          ;  ...save low  order status
  978.                                                 ;AX=(DEL Clear_To_Send) *    1
  979.                                                 ;   (DEL Data_Set_ready)*    2
  980.                                                 ;   (Trailing_Ring_Det.)*    4
  981.                                                 ;   (DEL Carrier_Detect)*    8
  982.                                                 ;   (    Clear_To_Send )*   16
  983.                                                 ;   (    Data_Set_Ready)*   32
  984.                                                 ;   (    Ring_Indicator)*   64
  985.                                                 ;   (    Carrier_Detect)*  128
  986.                                                 ;        **************
  987.                                                 ;   (    Char  received)*  256
  988.                                                 ;   (    Char smothered)*  512
  989.                                                 ;   (    Parity error  )* 1024
  990.                                                 ;   (    Framing error )* 2048
  991.                                                 ;   (    Break detected)* 4096
  992.                                                 ;   (    Able to xmit  )* 8192
  993.                                                 ;   (    Transmit idle )*16384
  994.                                                 ;   (    Time out error)*32768
  995.  
  996. POLL:   MOV     BL,byte ptr [DI+7Ch]            ; Wait on BH in status or error
  997.  
  998. POLL_1: SUB     CX,CX                           ; Outer delay loop
  999. POLL_2: IN      AL,DX                           ;  ...  inner loop
  1000.         MOV     AH,AL
  1001.         AND     AL,BH                           ; And status with user BH mask
  1002.         CMP     AL,BH
  1003.         JZ      POLLXT                          ;  ...  jump if mask set
  1004.         LOOP    POLL_2                          ; Else try again
  1005.         DEC     BL
  1006.         JNZ     POLL_1
  1007.         OR      BH,BH                           ; Clear mask to show timeout
  1008.  
  1009. POLLXT: RET                                     ; Exit AH reg. Z flag status
  1010.  
  1011. WAITFR: ADD     DX,4                            ; Reset the Modem Control Reg.
  1012.         OUT     DX,AL                           ;  ...index RS232_BASE + 4
  1013.         INC     DX                              ; Calculate Modem Status Reg.
  1014.         INC     DX                              ;  ...index RS232_BASE + 6
  1015.         PUSH    BX                              ; Save masks (BH=MSR,BL=LSR)
  1016.         CALL    POLL                            ; ...wait on MSR modem status
  1017.         POP     BX                              ; ...restore wait masks BH,BL
  1018.         JNZ     WAITF1                          ; ..."Error Somewhere" by DEC
  1019.  
  1020.         DEC     DX                              ; Calculate Line Status Reg.
  1021.         MOV     BH,BL                           ;  ...index RS232_BASE + 5
  1022.         CALL    POLL                            ;  ...wait on LSR line status
  1023.  
  1024. WAITF1: RET                                     ; Status in AH reg. and Z flag
  1025.  
  1026.         ENTRY   0E82Eh                          ; IBM entry, key bios service
  1027.  
  1028. INT_16: STI                                     ; Keyboard bios services
  1029.         PUSH    DS
  1030.         PUSH    BX
  1031.         MOV     BX,40h
  1032.         MOV     DS,BX                           ; Load work segment
  1033.         OR      AH,AH
  1034.         JZ      KPD_RD                          ; Read keyboard buffer, AH=0
  1035.         DEC     AH
  1036.         JZ      KPD_WT                          ; Set Z if char  ready, AH=1
  1037.         DEC     AH
  1038.         JZ      KPD_SH                          ; Return shift in AL  , AH=2
  1039.  
  1040. KPD_XT: POP     BX                              ; Exit INT_16 keypad service
  1041.         POP     DS
  1042.         IRET
  1043.  
  1044. KPD_RD: CLI                                     ; No interrupts, alters buffer
  1045.         MOV     BX,DS:1Ah                       ;  ...point to buffer head
  1046.         CMP     BX,DS:1Ch                       ; If not equal to buffer tail
  1047.         JNZ     KPD_R1                          ;  ...char waiting to be read
  1048.         STI                                     ; Else allow interrupts
  1049.         JMP     KPD_RD                          ;  ...wait for him to type
  1050.  
  1051. KPD_R1: MOV     AX,[BX]                         ; Fetch the character
  1052.         INC     BX                              ;  ...point to next character
  1053.         INC     BX                              ;  ...char = scan code + shift
  1054.         MOV     DS:1Ah,BX                       ; Save position in head
  1055.         CMP     BX,DS:82h                       ;  ...buffer overflowed?
  1056.         JNZ     KPD_XT                          ;  ...no, done
  1057.         MOV     BX,DS:80h                       ; Else reset to point at start
  1058.         MOV     DS:1Ah,BX                       ;  ...and correct head position
  1059.         JMP     KPD_XT
  1060.  
  1061. KPD_WT: CLI                                     ; No interrupts, critical code
  1062.         MOV     BX,DS:1Ah                       ;  ...point to buffer head
  1063.         CMP     BX,DS:1Ch                       ;  ...equal buffer tail?
  1064.         MOV     AX,[BX]                         ;     (fetch, look ahead)
  1065.         STI                                     ; Enable interrupts
  1066.         POP     BX
  1067.         POP     DS
  1068.         RETF    2                               ; Do IRET, preserve flags
  1069.  
  1070. KPD_SH: MOV     AL,DS:17h                       ; Read keypad shift status
  1071.         JMP     KPD_XT
  1072.  
  1073.         ENTRY   0E885h                          ; Align INT_9 at correct place
  1074.  
  1075. ASCII   db      000h,037h,02Eh,020h             ; Scan -> Ascii.  Sign bit set
  1076.         db      02Fh,030h,031h,021h             ;  ...if further work needed
  1077.         db      032h,033h,034h,035h
  1078.         db      022h,036h,038h,03Eh
  1079.         db      011h,017h,005h,012h
  1080.         db      014h,019h,015h,009h
  1081.         db      00Fh,010h,039h,03Ah
  1082.         db      03Bh,084h,001h,013h
  1083.         db      004h,006h,007h,008h
  1084.         db      00Ah,00Bh,00Ch,03Fh
  1085.         db      040h,041h,082h,03Ch
  1086.         db      01Ah,018h,003h,016h
  1087.         db      002h,00Eh,00Dh,042h
  1088.         db      043h,044h,081h,03Dh
  1089.         db      088h,02Dh,0C0h,023h
  1090.         db      024h,025h,026h,027h
  1091.         db      028h,029h,02Ah,02Bh
  1092.         db      02Ch,0A0h,090h
  1093.  
  1094. NOALFA  db      032h,036h,02Dh,0BBh             ; Non-Alphabetic secondary
  1095.         db      0BCh,0BDh,0BEh,0BFh             ;  ...translation table
  1096.         db      0C0h,0C1h,0C2h,0C3h
  1097.         db      0C4h,020h,031h,033h
  1098.         db      034h,035h,037h,038h
  1099.         db      039h,030h,03Dh,01Bh
  1100.         db      008h,05Bh,05Dh,00Dh
  1101.         db      05Ch,02Ah,009h,03Bh
  1102.         db      027h,060h,02Ch,02Eh
  1103.         db      02Fh
  1104.  
  1105. CTRLUP  db      040h,05Eh,05Fh,0D4h             ; CTRL uppercase secondary
  1106.         db      0D5h,0D6h,0D7h,0D8h             ;  ...translation table
  1107.         db      0D9h,0DAh,0DBh,0DCh             ;  ...for non-ASCII control
  1108.         db      0DDh,020h,021h,023h
  1109.         db      024h,025h,026h,02Ah
  1110.         db      028h,029h,02Bh,01Bh
  1111.         db      008h,07Bh,07Dh,00Dh
  1112.         db      07Ch,005h,08Fh,03Ah
  1113.         db      022h,07Eh,03Ch,03Eh
  1114.         db      03Fh
  1115.  
  1116. CTRLLO  db      003h,01Eh,01Fh,0DEh             ; CTRL lowercase secondary
  1117.         db      0DFh,0E0h,0E1h,0E2h             ;  ...translation table
  1118.         db      0E3h,0E4h,0E5h,0E6h             ;  ...for non-ASCII control
  1119.         db      0E7h,020h,005h,005h
  1120.         db      005h,005h,005h,005h
  1121.         db      005h,005h,005h,01Bh
  1122.         db      07Fh,01Bh,01Dh,00Ah
  1123.         db      01Ch,0F2h,005h,005h
  1124.         db      005h,005h,005h,005h
  1125.         db      005h
  1126.  
  1127. ALTKEY  db      0F9h,0FDh,002h,0E8h             ; ALT key secondary
  1128.         db      0E9h,0EAh,0EBh,0ECh             ;  ...translation table
  1129.         db      0EDh,0EEh,0EFh,0F0h
  1130.         db      0F1h,020h,0F8h,0FAh
  1131.         db      0FBh,0FCh,0FEh,0FFh
  1132.         db      000h,001h,003h,005h
  1133.         db      005h,005h,005h,005h
  1134.         db      005h,005h,005h,005h
  1135.         db      005h,005h,005h,005h
  1136.         db      005h
  1137.  
  1138. NUMPAD  db      '789-456+1230.'                 ; Keypad secondary tralsator
  1139.  
  1140. NUMCTR  db      0F7h,005h,004h,005h             ; Numeric keypad CTRL sec.
  1141.         db      0F3h,005h,0F4h,005h             ;  ...translation table
  1142.         db      0F5h,005h,0F6h,005h
  1143.         db      005h
  1144.  
  1145. NUMUPP  db      0C7h,0C8h,0C9h,02Dh             ; Numeric keypad SHIFT sec.
  1146.         db      0CBh,005h,0CDh,02Bh             ;  ...translation table
  1147.         db      0CFh,0D0h,0D1h,0D2h
  1148.         db      0D3h
  1149.  
  1150. INT_9:  STI                                     ; Key press hardware interrupt
  1151.         PUSH    AX
  1152.         PUSH    BX
  1153.         PUSH    CX
  1154.         PUSH    DX
  1155.         PUSH    SI
  1156.         PUSH    DI
  1157.         PUSH    DS
  1158.         PUSH    ES
  1159.         CLD
  1160.         MOV     AX,40h
  1161.         MOV     DS,AX
  1162.         IN      AL,60h                          ; Read the scan code data
  1163.         PUSH    AX                              ;  ...save it
  1164.         IN      AL,61h                          ; Get control port status
  1165.         PUSH    AX                              ;  ...save it
  1166.         OR      AL,10000000b                    ; Set "latch" bit to
  1167.         OUT     61h,AL                          ;  ...acknowledge data
  1168.         POP     AX                              ; Restore control status
  1169.         OUT     61h,AL                          ;  ...to enable keyboard
  1170.         POP     AX                              ;  ...restore scan code
  1171.         MOV     AH,AL                           ; Save copy of scan code
  1172.         CMP     AL,11111111b                    ;  ...check for overrun
  1173.         JNZ     KY_01                           ;  ...no, OK
  1174.         JMP     KY_BEP                          ; Else beep bell on overrun
  1175.  
  1176. KY_EOI: MOV     AL,20h                          ; Send end_of_interrupt code
  1177.         OUT     20h,AL                          ;  ...to 8259 interrupt chip
  1178.  
  1179. KY_XIT: POP     ES                              ; Exit the interrupt
  1180.         POP     DS
  1181.         POP     DI
  1182.         POP     SI
  1183.         POP     DX
  1184.         POP     CX
  1185.         POP     BX
  1186.         POP     AX
  1187.         IRET
  1188.  
  1189. KY_01:  AND     AL,01111111b                    ; Valid scan code, no break
  1190.         CMP     AL,46h
  1191.         JBE     KY_02
  1192.         JMP     KY_CT8
  1193.  
  1194. KY_02:  MOV     BX,offset ASCII                 ; Table for ESC thru Scroll Lck
  1195.         XLAT    CS:[BX]                         ;  ...translate to Ascii
  1196.         OR      AL,AL                           ; Sign flags "Shift" type key
  1197.         JS      KY_FLG                          ;  ...shift,caps,num,scroll etc
  1198.         OR      AH,AH                           ; Invalid scan code?
  1199.         JS      KY_EOI                          ;  ...exit if so
  1200.         JMP     short   KY_ASC                  ; Else normal character
  1201.  
  1202. KY_FLG: AND     AL,01111111b                    ; Remove sign flag bit
  1203.         OR      AH,AH                           ;  ...check scan code
  1204.         JS      KY_SUP                          ;  ...negative, key released
  1205.         CMP     AL,10h                          ; Is it a "toggle" type key?
  1206.         JNB     KY_TOG                          ;  ...yes
  1207.         OR      DS:17h,AL                       ; Else set bit in "flag" byte
  1208.         JMP     KY_EOI                          ;  ...and exit
  1209.  
  1210. KY_TOG: TEST    Byte ptr DS:17h,00000100b       ; Control key pressed?
  1211.         JNZ     KY_ASC                          ;  ...yes, skip
  1212.         TEST    AL,DS:18h                       ; Else check "CAPS, NUM, SCRL"
  1213.         JNZ     KY_EOI                          ;  ...set, invalid, exit
  1214.         OR      DS:18h,AL                       ; Show set in "flag_1" byte
  1215.         XOR     DS:17h,AL                       ;  ...flip bits in "flag" byte
  1216.         JMP     KY_EOI
  1217.  
  1218. KY_SUP: CMP     AL,10h                          ; Released - is it "toggle" key
  1219.         JNB     KY_TUP                          ;  ...skip if so
  1220.         NOT     AL                              ; Else form two's complement
  1221.         AND     DS:17h,AL                       ;  ...to do BIT_CLEAR "flags"
  1222.         CMP     AL,11110111b                    ; ALT key release special case
  1223.         JNZ     KY_EOI                          ;  ...no, exit
  1224.         MOV     AL,DS:19h                       ; Else get ALT-keypad character
  1225.         MOV     AH,0                            ;  ...pretend null scan code
  1226.         MOV     DS:19h,AH                       ;  ...zero ALT-keypad character
  1227.         CMP     AL,AH                           ; Was there a valid ALT-keypad?
  1228.         JZ      KY_EOI                          ;  ...no, ignore, exit
  1229.         JMP     KY_NUL                          ; Else stuff it in ASCII buffer
  1230.  
  1231. KY_TUP: NOT     AL                              ; Form complement of toggle key
  1232.         AND     DS:18h,AL                       ;  ...to do BIT_CLEAR "flag_1"
  1233.         JMP     KY_EOI
  1234.  
  1235. KY_ASC: TEST    Byte ptr DS:18h,00001000b       ; Scroll lock pressed?
  1236.         JZ      KY_NLK                          ;  ...no
  1237.         CMP     AH,45h                          ; Is this a NUM LOCK character?
  1238.         JZ      KY_03                           ;  ...no
  1239.         AND     Byte ptr DS:18h,11110111b       ; Else clear bits in "flag_1"
  1240.  
  1241. KY_03:  JMP     KY_EOI                          ;  ...and exit
  1242.  
  1243. KY_NLK: TEST    Byte ptr DS:17h,00001000b       ; ALT key pressed?
  1244.         JNZ     KY_ALT                          ;  ...yes
  1245.         TEST    Byte ptr DS:17h,00000100b       ; CTRL key pressed?
  1246.         JNZ     KY_CTL                          ;  ...yes
  1247.         TEST    Byte ptr DS:17h,00000011b       ; Either shift key pressed?
  1248.         JNZ     KSHIFT                          ;  ...yes
  1249.  
  1250. KY_LC:  CMP     AL,1Ah                          ; Alphabetic character?
  1251.         JA      KY_LC1                          ;  ...no
  1252.         ADD     AL,'a'-1                        ; Else add lower case base
  1253.         JMP     KY_COM
  1254.  
  1255. KY_LC1: MOV     BX,offset NOALFA                ; Non-alphabetic character
  1256.         SUB     AL,20h
  1257.         XLAT    CS:[BX]                         ;  ...do the xlate
  1258.         JMP     KY_COM
  1259.  
  1260. KY_ALT: CMP     AL,1Ah                          ; Control key pressed?
  1261.         JA      KY_AGN                          ;  ...no, skip
  1262.         MOV     AL,0                            ; Else illegal key press
  1263.         JMP     KY_BFR
  1264.  
  1265. KY_AGN: MOV     BX,offset ALTKEY                ; Load ALT key translation
  1266.         SUB     AL,20h                          ;  ...bias to printing char.
  1267.         XLAT    CS:[BX]                         ;  ...do the translation
  1268.         JMP     KY_COM
  1269.  
  1270. KY_CTL: CMP     AH,46h                          ; Scroll lock key?
  1271.         JNZ     KY_CT1                          ;  ...no, skip
  1272.         MOV     Byte ptr DS:71h,10000000b       ; Else CTRL-"Scroll" = break
  1273.         MOV     AX,DS:80h                       ;  ...get key buffer start
  1274.         MOV     DS:1Ch,AX                       ;  ...get key tail to start
  1275.         MOV     DS:1Ah,AX                       ;  ...get key head to start
  1276.         INT     1Bh                             ; Issue a "Break" interrupt
  1277.         SUB     AX,AX
  1278.         JMP     KY_CO2
  1279.  
  1280. KY_CT1: CMP     AH,45h                          ; Num lock key?
  1281.         JNZ     KY_CT2                          ;  ...no, skip
  1282.         OR      Byte ptr DS:18h,00001000b       ; Else show scroll lock
  1283.         MOV     AL,20h                          ;  ...send end_of_interrupt
  1284.         OUT     20h,AL                          ;  ...to 8259 int. controller
  1285.         CMP     Byte ptr DS:49h,7               ; Monochrome monitor?
  1286.         JZ      KY_POL                          ;  ...yes, skip
  1287.         MOV     DX,3D8h                         ; Else reset mode
  1288.         MOV     AL,DS:65h                       ;  ...for the
  1289.         OUT     DX,AL                           ;  ...CGA color card
  1290.  
  1291. KY_POL: TEST    Byte ptr DS:18h,00001000b       ; Wait for him to type
  1292.         JNZ     KY_POL                          ;  ...not yet
  1293.         JMP     KY_XIT
  1294.  
  1295. KY_CT2: CMP     AH,3                            ; Is it a Control @ (null) ?
  1296.         JNZ     KY_CT3                          ;  ...no
  1297.         MOV     AL,0                            ; Else force a null
  1298.  
  1299. KY_CT4: JMP     KY_BFR                          ;  ...save in buffer
  1300.  
  1301. KY_CT3: CMP     AL,1Ah                          ; Is it a control character?
  1302.         JBE     KY_CT4                          ;  ...yes
  1303.         MOV     BX,offset CTRLLO                ; Else non-ascii control
  1304.         SUB     AL,20h                          ;  ...lower case
  1305.         XLAT    CS:[BX]                         ;  ...translation
  1306.         JMP     KY_COM
  1307.  
  1308. KSHIFT: CMP     AH,37h                          ; Print_Screen pressed?
  1309.         JNZ     KY_CT5
  1310.         MOV     AL,20h                          ; Yes, send end_of_interrupt
  1311.         OUT     20h,AL                          ;  ...to 8259 interrupt chip
  1312.         INT     5                               ; Request print_screen service
  1313.         JMP     KY_XIT                          ;  ...and exit key service
  1314.  
  1315. KY_CT5: CMP     AL,1Ah                          ; Alphabetic char?
  1316.         JA      KY_CT6                          ;  ...no
  1317.         ADD     AL,'A'-1                        ; Yes, add base for alphabet
  1318.         JMP     KY_COM
  1319.  
  1320. KY_CT6: MOV     BX,offset CTRLUP                ; Non-ascii control
  1321.         SUB     AL,20h                          ;  ...upper case
  1322.         XLAT    CS:[BX]                         ;  ...translation
  1323.         JMP     KY_COM
  1324.  
  1325. KY_CT8: SUB     AL,47h                          ; Keypad key, convert origin
  1326.         MOV     BL,DS:17h                       ;  ...get "flag" byte
  1327.         TEST    BL,00001000b                    ; Look for ALT keypad entry
  1328.         JNZ     KB_NUM                          ;  ...do special entry thing
  1329.         TEST    BL,00000100b                    ; CTRL key pressed?
  1330.         JNZ     KY_CTR                          ;  ...skip if so
  1331.         TEST    BL,00100000b                    ; Toggle "Num Lock" ?
  1332.         JZ      KY_CT9                          ;  ...no, continue
  1333.         TEST    BL,00000011b                    ; Shift keys hit?
  1334.         JNZ     KY_CTA                          ;  ...no, check "INS"
  1335.         JMP     KY_CTD                          ; Else xlat keypad char.
  1336.  
  1337. KY_CT9: TEST    BL,00000011b                    ; Shift keys hit?
  1338.         JZ      KY_CTA                          ;  ...no, check "INS" key
  1339.         JMP     KY_CTD                          ; Else xlat keypad char.
  1340.  
  1341. KB_NUM: OR      AH,AH                           ; ALT-keypad entry, scan code
  1342.         JS      KY_EO1                          ;  ...out of range
  1343.         TEST    Byte ptr DS:17h,00000100b       ; Else check CTRL state
  1344.         JZ      KY_PAD                          ;  ...not pressed, ALT keypad
  1345.  
  1346. KY_PAT: CMP     AH,53h                          ; Patch for CTRL ALT - toggle
  1347.         JNZ     KY_PA1                          ;  ...not a DEL (reset)
  1348.         MOV     Word ptr DS:72h,1234h           ; Ctrl-Alt-Del, set init flag
  1349.         JMP     WARM                            ;  ...do a warm reboot
  1350.  
  1351. KY_PA1: CMP     AH,4Ah                          ; Is it a keypad "-" ?
  1352.         JNZ     KY_PAD                          ;  ...no, skip
  1353.         PUSH    AX
  1354.         PUSH    BX
  1355.         PUSH    CX
  1356.         IN      AL,61h                          ; Read equipment flags
  1357.         XOR     AL,00001100b                    ;  ...toggle speed
  1358.         OUT     61h,AL                          ; Write new flags back
  1359.  
  1360.         MOV     AH,1                            ; Video func=Set cursor type
  1361.         MOV     CX,607h                         ;  ...start at 6, end at 7
  1362.         AND     AL,4                            ; Is turbo mode set?
  1363.         JZ      KY_CUR                          ;  ...no, keep big cursor
  1364.         MOV     CH,0                            ; Else set tiny cursor
  1365.  
  1366. KY_CUR: INT     10h                             ; Set cursor type service
  1367.         MOV     BX,DS:80h                       ;  ...get start of key buf
  1368.         MOV     DS:1Ah,BX                       ;  ...set head  to start
  1369.         MOV     DS:1Ch,BX                       ;  ...set tail  to start
  1370.         POP     CX
  1371.         POP     BX
  1372.         POP     AX
  1373.  
  1374. KY_PAD: MOV     BX,offset NUMPAD                ; Get keypad translation table
  1375.         XLAT    CS:[BX]                         ;  ...convert to number
  1376.         CMP     AL,'0'                          ; Is it a valid ASCII digit?
  1377.         JB      KY_EO1                          ;  ...no, ignore it
  1378.         SUB     AL,30h                          ; Else convert to number
  1379.         MOV     BL,AL                           ;  ...save a copy
  1380.         MOV     AL,DS:19h                       ; Get partial ALT-keypad sum
  1381.         MOV     AH,0Ah                          ;  ...times 10 (decimal)
  1382.         MUL     AH
  1383.         ADD     AL,BL                           ; Add in new digit to sum
  1384.         MOV     DS:19h,AL                       ;  ...save as new ALT entry
  1385.  
  1386. KY_EO1: JMP     KY_EOI                          ; End_of_interrupt, exit
  1387.  
  1388. KY_CTR: OR      AH,AH                           ; Key released?
  1389.         JS      KY_EO1                          ;  ...ignore if so
  1390.         MOV     BX,offset NUMCTR                ; Else Numeric Keypad Control
  1391.         XLAT    CS:[BX]                         ;  ...secondary translate
  1392.         JMP     short   KY_COM                  ;  ...and save it
  1393.  
  1394. KY_CTA: CMP     AH,0D2h                         ; Was "INS" key released?
  1395.         JNZ     KY_CTB
  1396.         AND     Byte ptr DS:18h,01111111b       ; Yes, clear "INS" in "FLAG_1"
  1397.         JMP     short   KY_EO1
  1398.  
  1399. KY_CTB: OR      AH,AH                           ; Key released?
  1400.         JS      KY_EO1                          ;  ...ignore if so
  1401.         CMP     AH,52h                          ; Else check for "INS" press
  1402.         JNZ     KY_CTC                          ;  ...not "INS" press
  1403.         TEST    Byte ptr DS:18h,10000000b       ; Was INS key in effect?
  1404.         JNZ     KY_EO1                          ;  ...yes, ignore
  1405.         XOR     Byte ptr DS:17h,10000000b       ; Else tog "INS" in "FLAG" byte
  1406.         OR      Byte ptr DS:18h,10000000b       ;  ...set "INS" in "FLAG_1" byte
  1407.  
  1408. KY_CTC: MOV     BX,offset NUMUPP                ; Numeric Keypad Upper Case
  1409.         XLAT    CS:[BX]                         ;  ...secondary translation
  1410.         JMP     short   KY_COM
  1411.  
  1412. KY_CTD: OR      AH,AH                           ; Was the key released?
  1413.         JS      KY_EO1                          ;  ...yes, ignore
  1414.         MOV     BX,offset NUMPAD                ; Load translation table
  1415.         XLAT    CS:[BX]                         ;  ...do translate
  1416.         JMP     short   KY_COM
  1417.  
  1418. KY_COM: CMP     AL,5                            ; Common entry, char in AL
  1419.         JZ      KY_EO2                          ;  ...Control E, ignore
  1420.         CMP     AL,4
  1421.         JA      KY_CO1                          ; Above Control D
  1422.  
  1423.         OR      AL,10000000b                    ; Else set sign flag
  1424.         JMP     short   KY_CO2
  1425.  
  1426. KY_CO1: TEST    AL,10000000b                    ; Is sign bit set?
  1427.         JZ      KY_CO3                          ;  ...skip if so
  1428.         AND     AL,01111111b                    ; Else mask sign off
  1429.  
  1430. KY_CO2: MOV     AH,AL                           ; Save in high order byte
  1431.         MOV     AL,0                            ;  ...set scan code to zero
  1432.  
  1433. KY_CO3: TEST    Byte ptr DS:17h,01000000b       ; Test for "CAPS LOCK" state
  1434.         JZ      KY_BFR                          ;  ...no, skip
  1435.         TEST    Byte ptr DS:17h,00000011b       ; Test for SHIFT key
  1436.         JZ      KY_CO4                          ;  ...skip if no shift
  1437.         CMP     AL,'A'                          ; Check for alphabetic key
  1438.         JB      KY_BFR                          ;  ...not SHIFT_able
  1439.         CMP     AL,'Z'                          ; Check for alphabetic key
  1440.         JA      KY_BFR                          ;  ...not SHIFT_able
  1441.         ADD     AL,20h                          ; Else do the shift
  1442.         JMP     short   KY_BFR
  1443.  
  1444. KY_CO4: CMP     AL,'a'                          ; Check for alphabetic key
  1445.         JB      KY_BFR                          ;  ...not SHIFT_able
  1446.         CMP     AL,'z'                          ; Check for Alphabetic key
  1447.         JA      KY_BFR                          ;  ...not SHIFT_able
  1448.         SUB     AL,20h                          ; Else do the shift
  1449.  
  1450. KY_BFR: MOV     BX,DS:1Ch                       ; BX = tail of buffer
  1451.         MOV     DI,BX                           ;  ...save it
  1452.         INC     BX                              ;  ...advance
  1453.         INC     BX                              ;  ...by word
  1454.         CMP     BX,DS:82h                       ; End of buffer reached?
  1455.         JNZ     KY_CHK                          ;  ...no, skip
  1456.         MOV     BX,DS:80h                       ; Else BX = beginning of buffer
  1457.  
  1458. KY_CHK: CMP     BX,DS:1Ah                       ; BX = Buffer Head ?
  1459.         JNZ     KY_STF                          ;  ...no, OK
  1460.         JMP     short   KY_BEP                  ; Else buffer overrun, beep
  1461.  
  1462. KY_STF: MOV     [DI],AX                         ; Stuff scan code, char in bfr
  1463.         MOV     DS:1Ch,BX                       ;  ...and update bfr tail
  1464.  
  1465. KY_EO2: JMP     KY_EOI
  1466.  
  1467. KY_BEP: MOV     AL,20h                          ; Keyboard beeper routine
  1468.         OUT     20h,AL                          ;  ...send end_of_interrupt
  1469.         MOV     BX,80h                          ; Cycles in beep
  1470.         IN      AL,61h                          ;  ...get status
  1471.         PUSH    AX                              ;  ...save copy
  1472.  
  1473. KY_BE1: AND     AL,11111100b                    ; Mask off speaker bits
  1474.         OUT     61h,AL                          ;  ...disable speaker
  1475. KY_BE2: MOV     CX,64h                          ; Constant for pitch
  1476. KY_BE3: LOOP    KY_BE3                          ;  ...delay, speaker off
  1477.         XOR     AL,00000010b
  1478.         OUT     61h,AL                          ; Toggle speaker position
  1479.         TEST    AL,00000010b                    ; Full cycle done yet?
  1480.         JZ      KY_BE2                          ;  ...no, do other half cycle
  1481.         DEC     BX                              ; Else show cycle sent
  1482.         JNZ     KY_BE1                          ;  ...more cycles to send
  1483.         POP     AX
  1484.         OUT     61h,AL                          ; Restore flags
  1485.         MOV     CX,32h                          ; Silence counter
  1486. KY_BE4: LOOP    KY_BE4                          ; Send nothing for while
  1487.         JMP     KY_XIT
  1488.  
  1489. KY_NUL: MOV     AH,38h                          ; ALT key pressed, released
  1490.         JMP     KY_BFR                          ;  ...for no logical reason
  1491.  
  1492.         ENTRY   0EC59h                          ; IBM entry point for floppy
  1493.  
  1494. INT_13: STI                                     ; Floppy disk services
  1495.         PUSH    BP
  1496.         PUSH    SI
  1497.         PUSH    DI
  1498.         PUSH    DS
  1499.         PUSH    ES
  1500.         PUSH    BX
  1501.         MOV     DI,AX                           ; Request type in DI, for index
  1502.         XOR     AX,AX
  1503.         MOV     DS,AX
  1504.         LES     SI,Dword ptr DS:78h             ; Get disk parameter table
  1505.         MOV     AX,40h
  1506.         MOV     DS,AX
  1507.         MOV     BX,5
  1508.         MOV     AX,ES:[BX+SI]                   ; Get (Gap Length, DTL) in AX
  1509.         PUSH    AX                              ;  ...save it
  1510.         DEC     BX
  1511.         DEC     BX
  1512.         MOV     AX,ES:[BX+SI]                   ; Get (Bytes/sector,EOT) in AX
  1513.         PUSH    AX                              ;  ...save it
  1514.         XCHG    CL,DH
  1515.         XCHG    DL,CL
  1516.         PUSH    DX                              ; Push (Head,Drive) swapped
  1517.         PUSH    CX
  1518.         PUSH    DI
  1519.         MOV     BP,SP                           ; Mark bottom of stack frame
  1520. ifdef   SLOW_FLOPPY
  1521.         CALL    FD_SPD                          ;  ...execute request lo speed
  1522. else
  1523.         CALL    FD_XQT                          ;  ...execute at current speed
  1524. endif
  1525.         MOV     AH,ES:[SI+2]                    ; Get new motor count
  1526.         MOV     DS:40h,AH                       ;  ...and save it
  1527.         MOV     AH,DS:41h                       ; Get completion status
  1528.         CMP     AH,1                            ;  ...check for write protect
  1529.         CMC                                     ;  ...was write protect error
  1530.         POP     BX
  1531.         POP     CX
  1532.         POP     DX
  1533.         XCHG    DL,CL
  1534.         XCHG    CL,DH
  1535.         POP     BX                              ; Clean
  1536.         POP     BX                              ;  ...up
  1537.         POP     BX                              ;  ...stack
  1538.         POP     ES
  1539.         POP     DS
  1540.         POP     DI
  1541.         POP     SI
  1542.         POP     BP
  1543.         RETF    2
  1544.  
  1545. FD_XQT: MOV     AL,[BP+1]                       ; Get floppy service number
  1546.         OR      AL,AL
  1547.         JZ      FD_RST                          ;  ...reset, AH=0
  1548.         DEC     AL
  1549.         JZ      FD_XQ3                          ;  ...read status, AH=1
  1550.         CMP     Byte ptr [BP+2],3               ; For track number above 3?
  1551.         JA      FD_XQ1                          ;  ...yes
  1552.         CMP     AL,5                            ; Service within range?
  1553.         JBE     FD_XQ2                          ; ...yes
  1554.  
  1555. FD_XQ1: MOV     Byte ptr DS:41h,1               ; Say write protect error
  1556.         RET
  1557.  
  1558. FD_XQ2: JMP     FD_001                          ; Execute legal service
  1559.  
  1560. FD_XQ3: MOV     AL,DS:41h                       ; Return NEC status byte
  1561.         RET
  1562.  
  1563. FD_RST: MOV     DX,3F2h                         ; Reset the floppy disk system
  1564.         CLI
  1565.         AND     Byte ptr DS:3Fh,00001111b       ; Clear "write in progress"
  1566.         MOV     AL,DS:3Fh                       ;  ...find out busy drives
  1567.         MOV     CL,4
  1568.         SHL     AL,CL
  1569.         TEST    AL,00100000b
  1570.         JNZ     FD_RS1                          ; Drive #1 active
  1571.         TEST    AL,01000000b
  1572.         JNZ     FD_RS2                          ; Drive #2 active
  1573.         TEST    AL,10000000b
  1574.         JZ      FD_RS0                          ; Drive #3 idle
  1575.  
  1576. FD_RS3: INC     AL
  1577. FD_RS2: INC     AL
  1578. FD_RS1: INC     AL
  1579.  
  1580. FD_RS0: MOV     Byte ptr DS:3Eh,0               ; All drives need recalibrate
  1581.         MOV     Byte ptr DS:41h,0               ;  ...no completion status
  1582.         OR      AL,00001000b                    ; Interrupt ON in command word
  1583.         OUT     DX,AL                           ;  ...send word to controller
  1584.         OR      AL,00000100b                    ; "Reset" in command word
  1585.         OUT     DX,AL                           ;  ...send word to controller
  1586.         STI
  1587.         CALL    NC_BSY                          ; Wait for completion
  1588.         CALL    NC_STS                          ;  ...read result block
  1589.         MOV     AL,DS:42h
  1590.         CMP     AL,0C0h                         ; Did the reset work
  1591.         JZ      FD_RS4                          ;  ...yes
  1592.         MOV     Byte ptr DS:41h,20h             ; Else set controller error
  1593.         JMP     short   FD_RS5                  ;  ...return
  1594.  
  1595. FD_RS4: MOV     AL,3                            ; Specify command to NEC
  1596.         CALL    NEC765                          ;  ...send it
  1597.         MOV     AL,ES:[SI]                      ; First byte in param block
  1598.         CALL    NEC765                          ;  ...send it
  1599.         MOV     AL,ES:[SI+1]                    ; Secnd byte in param block
  1600.         CALL    NEC765                          ;  ...send it
  1601.  
  1602. FD_RS5: RET
  1603.  
  1604. NECFUN  db      003h,000h,0E6h,0C5h,0E6h,04Dh   ; NEC function table lookup
  1605. NECDMA  db      000h,000h,046h,04Ah,042h,04Ah   ; DMA modes for 8237
  1606. NECWRT  db      000h,000h,000h,080h,000h,080h   ; Write flag   table lookup
  1607. NECDRV  db      1,2,4,8                         ; Drive number table lookup
  1608. NECERR  db      80h,20h,10h,4,2,1               ; Error code   table lookup
  1609. NECSTS  db      04h,10h,08h,04h,03h,02h,20h     ; Disk status  table lookup
  1610.  
  1611. FD_001: CLI                                     ; Normal (non-reset) commands
  1612.         MOV     Byte ptr DS:41h,0               ;  ...reset status
  1613.         MOV     AL,[BP+1]                       ; Get command word
  1614.         MOV     AH,0
  1615.         MOV     DI,AX                           ; Save copy, zero-extended
  1616.         OUT     0Ch,AL                          ;  ...diddle LSB/MSB flip-flop
  1617.         MOV     AL,CS:[DI+NECDMA]               ; Fetch DMA mode
  1618.         OUT     0Bh,AL                          ;  ...send it to IC8237
  1619.         MOV     AX,[BP+0Ch]                     ; Get segment address
  1620.         MOV     CL,4                            ;  ...convert
  1621.         ROL     AX,CL                           ;  ...to (offset, 64K page no)
  1622.         MOV     CH,AL                           ; Extract page number (0-15.)
  1623.         AND     CH,00001111b                    ;  ...for 8237 dma controller
  1624.         AND     AL,11110000b                    ; Extract implicit page offset
  1625.         ADD     AX,[BP+0Ah]                     ;  ...add explicit user offset
  1626.         ADC     CH,0                            ;  ...(page number overflowed)
  1627.         MOV     DX,AX                           ; Now save lo 16 bits of addr.
  1628.         OUT     4,AL                            ;  ...send lowest 8 bits  " "
  1629.         MOV     AL,AH
  1630.         OUT     4,AL                            ;  ...send next   8 bits  " "
  1631.         MOV     AL,CH
  1632.         OUT     81h,AL                          ; 64K page no to DMA page reg
  1633.         MOV     AH,[BP+0]
  1634.         MOV     AL,0
  1635.         SHR     AX,1                            ; Sector cnt * 128
  1636.         MOV     CL,[BP+6]                       ; Track count
  1637.         SHL     AX,CL                           ;  * sector count
  1638.         DEC     AX                              ; - 1
  1639.         OUT     5,AL                            ; Send 1/2 of the word count
  1640.         XCHG    AL,AH
  1641.         OUT     5,AL                            ; Send 2/2 of the word count
  1642.         XCHG    AL,AH
  1643.         ADD     AX,DX                           ; Compute final address
  1644.         JNB     FD_002                          ;  ...ok
  1645.         STI
  1646.         MOV     Byte ptr DS:41h,9h              ; Else wrapped around 64K byte
  1647.         JMP     FD_64K                          ;  ...page register
  1648.  
  1649. FD_002: MOV     AL,2                            ; Disable floppy disk dma
  1650.         OUT     0Ah,AL
  1651.         MOV     Byte ptr DS:40h,0FFh            ; Set large motor timeout
  1652.         MOV     BL,[BP+2]                       ;  ...get drive number
  1653.         MOV     BH,0
  1654.         MOV     AL,CS:[BX+NECDRV]               ; Table lookup bit position
  1655.         MOV     CH,AL                           ;  ...save mask
  1656.         MOV     CL,4
  1657.         SHL     AL,CL                           ; Shift mask into place
  1658.         OR      AL,BL                           ;  ...or in drive select
  1659.         OR      AL,0Ch                          ;  ...or in DMA and NO RESET
  1660.         MOV     DX,3F2h
  1661.         OUT     DX,AL                           ; Send to floppy control port
  1662.         STI
  1663.         MOV     AL,CS:[DI+NECWRT]               ; Table lookup for write  flag
  1664.         OR      DS:3Fh,AL                       ;  ...set write flag if active
  1665.         OR      AL,AL
  1666.         JNS     FD_003                          ;  ...skip if non-write
  1667.         MOV     AH,ES:[SI+0Ah]                  ; Motor start from param blk
  1668.         OR      AH,AH
  1669.         JZ      FD_003                          ;  ...none specified
  1670.         TEST    CH,DS:3Fh                       ; Was this drive motor running?
  1671.         JNZ     FD_003                          ;  ...skip if so
  1672.         CALL    FD_WT1                          ; Else delay for motor start
  1673.  
  1674. FD_003: OR      DS:3Fh,CH                       ; Show this motor is running
  1675.         TEST    CH,DS:3Eh                       ; Drive recalibration needed?
  1676.         JNZ     FD_004                          ;  ...no, skip
  1677.         OR      DS:3Eh,CH                       ; Else show recalibrated
  1678.         MOV     AL,7                            ; Send RECAL command
  1679.         CALL    NEC765                          ;  ...to NEC 765 chip
  1680.         MOV     AL,BL
  1681.         CALL    NEC765                          ;  ...drive number
  1682.         CALL    NC_BSY                          ; Wait for completion of RECAL
  1683.         CALL    NEC_04                          ;  ...dummy call to RET
  1684.  
  1685. FD_004: MOV     AL,0Fh                          ; Request a seek
  1686.         CALL    NEC765                          ;  ...from the NEC 765
  1687.         MOV     AL,BL
  1688.         CALL    NEC765                          ; Drive number
  1689.         MOV     AL,[BP+3]
  1690.         CALL    NEC765                          ; Cylinder number
  1691.         CALL    NC_BSY                          ;  ...wait for completion
  1692.         CALL    NC_STS                          ;  ...read results
  1693.         MOV     AL,ES:[SI+9]                    ; Get head settle time
  1694.         OR      AL,AL                           ;  ...none specified?
  1695.         JZ      FD_005                          ;  ...if none, skip
  1696.  
  1697. FD_STL: MOV     CX,226h                         ; Delay time for head settle
  1698.  
  1699. FD_STZ: LOOP    FD_STZ                          ;  ...timed wait
  1700.         DEC     AL                              ;  ...delay in millisec
  1701.         JNZ     FD_STL                          ;  ...wait some more
  1702.  
  1703. FD_005: MOV     AL,CS:[DI+NECFUN]               ; Translate user service, then
  1704.         CALL    NEC765                          ;  ...and send as NEC func
  1705.         MOV     AL,[BP+4]                       ;
  1706.         AND     AL,1
  1707.         SHL     AL,1
  1708.         SHL     AL,1
  1709.         OR      AL,BL
  1710.         CALL    NEC765
  1711.         CMP     Byte ptr [BP+1],5               ; Is this a format request?
  1712.         JNZ     FD_006                          ;  ...skip if not
  1713.         MOV     AL,[BP+6]                       ; Else use user bytes/sector
  1714.         CALL    NEC765
  1715.         MOV     AL,[BP+7]                       ;  ... user EOT
  1716.         CALL    NEC765
  1717.         MOV     AL,ES:[SI+7]                    ; Disk table format gap length
  1718.         CALL    NEC765
  1719.         MOV     AL,ES:[SI+8]                    ; Disk table format fill byte
  1720.         CALL    NEC765
  1721.         JMP     short   FD_008
  1722.  
  1723. FD_006: MOV     CX,7                            ; Else lookup bytes * 512/sec
  1724.         MOV     DI,3                            ;  ...from disk table
  1725.  
  1726. FD_007: MOV     AL,[BP+DI]                      ; AL has bytes/sector * 512
  1727.         CALL    NEC765
  1728.         INC     DI                              ;  ...get next item for table
  1729.         LOOP    FD_007                          ;  ...also (EOT,GAP,DTL...)
  1730.  
  1731. FD_008: CALL    NC_BSY                          ; Wait on floppy i/o completion
  1732.         CALL    NC_ST1                          ;  ...get NEC status
  1733.         MOV     AL,DS:42h                       ;  ...into AL
  1734.         AND     AL,11000000b                    ; Isolate errors
  1735.         JZ      FD_012                          ;  ...no errors
  1736.         CMP     AL,40h                          ; Test direction bit
  1737.         JZ      FD_ERR
  1738.         MOV     Byte ptr DS:41h,20h             ; Set if bad controller
  1739.         JMP     short   FD_012                  ;  ...return error
  1740.  
  1741. FD_ERR: MOV     AL,DS:43h                       ; Read return code from block
  1742.         MOV     CX,6                            ;  ...number of error types
  1743.         XOR     BX,BX                           ; Start at error type 0
  1744.  
  1745. FD_009: TEST    AL,CS:[BX+NECERR]               ; Has error type BX occured?
  1746.         JNZ     FD_010                          ;  ...yes
  1747.         INC     BX                              ; Else try next error type
  1748.         LOOP    FD_009                          ;  ...until done
  1749.  
  1750. FD_010: MOV     AL,CS:[BX+NECSTS]               ; Translate error code again
  1751.         MOV     DS:41h,AL                       ;  ...store it as disk status
  1752.  
  1753. FD_012: MOV     AL,DS:45h                       ; Get bytes read
  1754.         CMP     AL,[BP+3]                       ;  ...compare with requested
  1755.         MOV     AL,DS:47h                       ; Read sectors requested
  1756.         JZ      FD_013                          ;  ...return if all read
  1757.         MOV     AL,[BP+7]                       ; Else read sectors requested
  1758.         INC     AL                              ;  ...add one for luck
  1759.  
  1760. FD_013: SUB     AL,[BP+5]                       ; Subtract stectors read
  1761.         RET
  1762.  
  1763. FD_64K: MOV     AL,0                            ; Overflowed 64K page boundary
  1764.         RET                                     ;  ...show no sectors read
  1765.  
  1766. NC_BSY: STI                                     ; Wait for operation to finish
  1767.         XOR     CX,CX                           ;  ...zero lo order delay
  1768.         MOV     AL,2                            ; Load hi order delay
  1769.  
  1770. NC_BS1: TEST    Byte ptr DS:3Eh,10000000b       ; Has interrupt set the flag?
  1771.         CLC                                     ;  ...hack to slow CPU
  1772.         JNZ     NC_BS2                          ;  ...yes
  1773.         LOOP    NC_BS1                          ; Else back for more
  1774.         DEC     AL
  1775.         JNZ     NC_BS1
  1776.  
  1777.         MOV     Byte ptr DS:41h,80h             ; Time-out, say it completed
  1778.         POP     AX
  1779.         MOV     AL,0                            ;  ...return time out code
  1780.         STC                                     ;  ...error status
  1781.         RET
  1782.  
  1783. NC_BS2: AND     Byte ptr DS:3Eh,01111111b       ; Mask off completion status
  1784.         RET                                     ;  ...return carry clear
  1785.  
  1786. NC_RDY: PUSH    CX                              ; Wait for NEC ready for comand
  1787.         XOR     CX,CX
  1788.         MOV     DX,3F4h                         ;  ...NEC status port
  1789.  
  1790. NC_RD1: IN      AL,DX                           ; Read status of NEC 765 chip
  1791.         OR      AL,AL
  1792.         JS      NC_RD2                          ;  ...able to accept command
  1793.         LOOP    NC_RD1
  1794.         MOV     Byte ptr DS:41h,80h             ; Else show timeout error
  1795.         JMP     short   NC_RD3
  1796.  
  1797. NC_RD2: TEST    AL,01000000b                    ; Test the direction bit
  1798.         JNZ     NC_RD4
  1799.         MOV     Byte ptr DS:41h,20h             ;  ...clear iff controller err
  1800.  
  1801. NC_RD3: POP     CX
  1802.         STC
  1803.         RET
  1804.  
  1805. NC_RD4: INC     DX                              ; Load NEC data port
  1806.         IN      AL,DX                           ;  ...read it
  1807.         PUSH    AX
  1808.  
  1809.         MOV     CX,0Ah                          ; Short delay
  1810. NC_RD5: LOOP    NC_RD5
  1811.  
  1812.         DEC     DX                              ; Load NEC status port
  1813.         IN      AL,DX                           ;  ...read status
  1814.         TEST    AL,00010000b                    ;  ...set Z flag if done
  1815.         CLC                                     ;  ...return success
  1816.         POP     AX
  1817.         POP     CX
  1818.         RET
  1819.  
  1820. FD_WT1: PUSH    CX                              ; Millisecond delay in AH
  1821. FD_WT2: XOR     CX,CX
  1822. FD_WT3: LOOP    FD_WT3
  1823.         DEC     AH
  1824.         JNZ     FD_WT2
  1825.         POP     CX
  1826.         RET
  1827.  
  1828. ifdef   SLOW_FLOPPY                             ; Run floppy at SLOWEST speed
  1829.  
  1830. FD_SPD: IN      AL,61h                          ; Toggle speed on Floppy Disk
  1831.         PUSH    AX                              ;  ...save old clock rate
  1832.         AND     AL,11110011b                    ;  ...load slowest clock rate
  1833.         OUT     61h,AL                          ;  ...slow down to 4.77 mHz
  1834.         CALL    FD_XQT                          ; Execute the i/o request
  1835.         POP     AX                              ;  ...restore old clock rate
  1836.         OUT     61h,AL                          ;  ...from saved clock byte
  1837.         RET
  1838. endif
  1839.  
  1840.         ENTRY   0EF57h                          ; Disk interrupt entry
  1841.  
  1842. INT_E:  STI                                     ; Floppy disk attention
  1843.         PUSH    DS
  1844.         PUSH    AX
  1845.         MOV     AX,40h
  1846.         MOV     DS,AX
  1847.         OR      Byte ptr DS:3Eh,10000000b       ; Raise "attention" flag
  1848.         MOV     AL,20h                          ; Send end_of_interrupt code
  1849.         OUT     20h,AL                          ;  ...to 8259 interrupt chip
  1850.         POP     AX
  1851.         POP     DS
  1852.         IRET
  1853.  
  1854. NC_STS: MOV     AL,8                            ; Send a "Request status"
  1855.         CALL    NEC765                          ;  ...to the NEC 765 chip
  1856.  
  1857. NC_ST1: PUSH    BX                              ; Alternate entry point
  1858.         PUSH    CX
  1859.         MOV     CX,7
  1860.         XOR     BX,BX
  1861.  
  1862. NC_ST2: CALL    NC_RDY                          ; Wait for NEC 765 ready
  1863.         JB      NC_ST3                          ;  ...NEC 765 error
  1864.         MOV     [BX+42h],AL                     ; Save status in BIOS block
  1865.         JZ      NC_ST4                          ;  ...NEC 765 ready
  1866.         INC     BX                              ; Count more
  1867.         LOOP    NC_ST2
  1868.         MOV     Byte ptr DS:41h,20h             ; NEC 765 controller error
  1869.  
  1870. NC_ST3: STC                                     ; Set error condition
  1871.         POP     CX
  1872.         POP     BX
  1873.         POP     AX
  1874.         MOV     AL,0
  1875.         RET
  1876.  
  1877. NC_ST4: POP     CX                              ; Successful return
  1878.         POP     BX
  1879.         RET
  1880.  
  1881. NEC765: PUSH    CX                              ; Send control to NEC 765 chip
  1882.         PUSH    DX
  1883.         PUSH    AX
  1884.         XOR     CX,CX
  1885.         MOV     DX,3F4h                         ; Load NEC 765 status port
  1886.  
  1887. NEC_01: IN      AL,DX                           ; Read NEC 765 status
  1888.         OR      AL,AL
  1889.         JS      NEC_02                          ;  ...done
  1890.         LOOP    NEC_01
  1891.         MOV     Byte ptr DS:41h,80h             ; Set time out status
  1892.         JMP     short   NEC_05
  1893.  
  1894. NEC_02: TEST    AL,40h                          ; Check data direction
  1895.         JZ      NEC_03
  1896.         MOV     Byte ptr DS:41h,20h             ;  ...NEC 765 is gimped
  1897.         JMP     short   NEC_05
  1898.  
  1899. NEC_03: INC     DX                              ; Load NEC 765 data port
  1900.         POP     AX
  1901.         OUT     DX,AL                           ;  ...write user's parameter
  1902.         CLC
  1903.         POP     DX
  1904.         POP     CX
  1905. NEC_04: RET
  1906.  
  1907. NEC_05: POP     AX                              ; Common error return
  1908.         POP     DX
  1909.         POP     CX
  1910.         POP     AX
  1911.         MOV     AL,0
  1912.         STC
  1913.         RET
  1914.  
  1915.         ENTRY   0EFC7h                          ; IBM entry for disk param
  1916.  
  1917. INT_1E: db      11001111b                       ; Disk parameter table
  1918.         db      2
  1919.         db      25h
  1920.         db      2
  1921.         db      8
  1922.         db      2Ah
  1923.         db      0FFh
  1924.         db      50h
  1925.         db      0F6h
  1926.         db      19h
  1927.         db      4
  1928.  
  1929.         ENTRY   0EFD2h                          ; IBM entry for parallel LPT
  1930.  
  1931. INT_17: STI                                     ; Parallel printer services
  1932.         PUSH    DS
  1933.         PUSH    BX
  1934.         PUSH    CX
  1935.         PUSH    DX
  1936.         MOV     BX,40h
  1937.         MOV     DS,BX
  1938.         MOV     BX,DX                           ; DX is printer index (0 - 3)
  1939.         SHL     BX,1                            ;  ...word index
  1940.         MOV     DX,[BX+8]                       ; Load printer port
  1941.         OR      DX,DX
  1942.         JZ      LP_01                           ; Goes to black hole
  1943.         OR      AH,AH
  1944.         JZ      LP_02                           ; Function is print, AH=0
  1945.         DEC     AH
  1946.         JZ      LP_INI                          ; Function is init , AH=1
  1947.         DEC     AH
  1948.         JZ      LP_STS                          ; Get the status   , AH=2
  1949.  
  1950. LP_01:  POP     DX
  1951.         POP     CX
  1952.         POP     BX
  1953.         POP     DS
  1954.         IRET
  1955.  
  1956. LP_02:  OUT     DX,AL                           ; Char --> data lines 0-7
  1957.         INC     DX                              ; Printer status port
  1958.         MOV     BH,[BX+78h]                     ; Load time out parameter
  1959.         MOV     AH,AL
  1960.  
  1961. LP_05:  XOR     CX,CX                           ; Clear lo order time out
  1962.  
  1963. LP_POL: IN      AL,DX                           ; Get line printer status
  1964.         OR      AL,AL                           ;  ...ready?
  1965.         JS      LP_DON                          ;  ...done if so
  1966.         LOOP    LP_POL
  1967.         DEC     BH                              ; Decrement hi order time out
  1968.         JNZ     LP_05
  1969.  
  1970.         OR      AL,00000001b                    ; Set timeout in Status Byte
  1971.         AND     AL,11111001b                    ;  ...bits returned to caller
  1972.         JMP     short   LP_TOG
  1973.  
  1974. LP_DON: INC     DX                              ; Printer control port
  1975.         MOV     AL,00001101b                    ; Set output strobe hi
  1976.         OUT     DX,AL                           ;  ...data lines 0-7 valid
  1977.  
  1978. LP_STR: MOV     AL,00001100b                    ; Set output strobe lo
  1979.         OUT     DX,AL                           ;  ...data lines 0-7 ?????
  1980.         DEC     DX                              ; Printer status port
  1981.         JMP     short   LP_ST1                  ; ...get line printer status
  1982.  
  1983. LP_STS: MOV     AH,AL                           ; Save copy of character
  1984.         INC     DX                              ; Printer status port
  1985.  
  1986. LP_ST1: IN      AL,DX                           ; Read printer status
  1987.         AND     AL,11111000b                    ;  ...bits returned to caller
  1988.  
  1989. LP_TOG: XOR     AL,01001000b                    ;  ...toggle ERROR,ACKNOWLEDGE
  1990.         XCHG    AL,AH
  1991.         JMP     LP_01                           ; Exit, AH=Status,AL=character
  1992.  
  1993. LP_INI: MOV     AH,AL                           ; Initialize the line printer
  1994.         INC     DX
  1995.         INC     DX
  1996.         MOV     AL,00001000b
  1997.         OUT     DX,AL                           ; Request initialize
  1998.         MOV     CX,5DCh                         ;  ...delay
  1999. LP_DLY: LOOP    LP_DLY
  2000.         JMP     LP_STR                          ; Strobe the line printer
  2001.  
  2002.         ENTRY   0F045h                          ; IBM entry point for table
  2003.  
  2004. V_TABLE dw      CRT_0                           ; Set mode
  2005.         dw      CRT_1                           ; Set cursor type
  2006.         dw      CRT_2                           ; Set cursor position
  2007.         dw      CRT_3                           ; Get cursor position
  2008.         dw      CRT_4                           ; Read light pen position
  2009.         dw      CRT_5                           ; Set active display page
  2010.         dw      CRT_6                           ; Scroll active page up
  2011.         dw      CRT_7                           ; Scroll active page down
  2012.         dw      CRT_8                           ; Read attribute/character
  2013.         dw      CRT_9                           ; Write attribute/character
  2014.         dw      CRT_10                          ; Read character only
  2015.         dw      CRT_11                          ; Set color
  2016.         dw      CRT_12                          ; Write pixel
  2017.         dw      CRT_13                          ; Read  pixel
  2018.         dw      CRT_14                          ; Write teletype
  2019.         dw      CRT_15                          ; Return current video state
  2020.  
  2021.         ENTRY   0F065h                          ; IBM entry, video bios service
  2022.  
  2023. INT_10: STI                                     ; Video bios service AH=(0-15.)
  2024.         CLD                                     ;  ...strings auto-increment
  2025.         PUSH    BP
  2026.         PUSH    ES
  2027.         PUSH    DS
  2028.         PUSH    SI
  2029.         PUSH    DI
  2030.         PUSH    DX
  2031.         PUSH    CX
  2032.         PUSH    BX
  2033.         PUSH    AX
  2034.         MOV     BX,40h
  2035.         MOV     DS,BX
  2036.         MOV     BL,DS:10h                       ; Get equipment byte
  2037.         AND     BL,00110000b                    ;  ...isolate video mode
  2038.         CMP     BL,00110000b                    ; Check for monochrome card
  2039.         MOV     BX,0B800h
  2040.         JNZ     C_01                            ; ...not there, BX --> CGA
  2041.         MOV     BX,0B000h                       ; Else          BX --> MONO
  2042.  
  2043. C_01:   PUSH    BX                              ; Save video buffer address
  2044.         MOV     BP,SP                           ;  ...start of stack frame
  2045.         CALL    C_02                            ;  ...then do the function
  2046.         POP     SI
  2047.         POP     AX
  2048.         POP     BX
  2049.         POP     CX
  2050.         POP     DX
  2051.         POP     DI
  2052.         POP     SI
  2053.         POP     DS
  2054.         POP     ES
  2055.         POP     BP
  2056.         IRET
  2057.  
  2058. MAPBYT: PUSH    DX                              ; Mul AL by BX, CX --> buf
  2059.         MOV     AH,0
  2060.         MUL     BX                              ; Position in AX
  2061.         POP     DX
  2062.         MOV     CX,[BP+0]                       ; CX --> video buffer
  2063.         RET
  2064.  
  2065.         ENTRY   0F0A4h                          ; IBM entry, SET_MODE tables
  2066.  
  2067. INT_1D: db      38h,28h,2Dh,0Ah,1Fh,6,19h       ; Init string for 40 x 25
  2068.         db      1Ch,2,7,6,7
  2069.         db      0,0,0,0
  2070.  
  2071.         db      71h,50h,5Ah,0Ah,1Fh,6,19h       ; Init string for 80 x 25 col
  2072.         db      1Ch,2,7,6,7
  2073.         db      0,0,0,0
  2074.  
  2075.         db      38h,28h,2Dh,0Ah,7Fh,6,64h       ; Init string for GRAPHIX
  2076.         db      70h,2,1,6,7
  2077.         db      0,0,0,0
  2078.  
  2079.         db      61h,50h,52h,0Fh,19h,6,19h       ; Init string for 80 x 25 b/w
  2080.         db      19h,2,0Dh,0Bh,0Ch
  2081.         db      0,0,0,0
  2082.  
  2083. REGENL  dw      0800h                           ; Regen len, 40 x 25
  2084.         dw      1000h                           ;            80 x 25
  2085.         dw      4000h                           ;            GRAPHIX
  2086.         dw      4000h
  2087.  
  2088. MAXCOL  db      28h,28h,50h,50h,28h,28h,50h,50h ; Maximum columns
  2089.  
  2090. MODES   db      2Ch,28h,2Dh,29h,2Ah,2Eh,1Eh,29h ; Table of mode sets
  2091.  
  2092. TABMUL  db      00h,00h,10h,10h,20h,20h,20h,30h ; Table lookup for multiply
  2093.  
  2094. C_02:   CMP     AH,0Fh                          ; Is AH a legal video command?
  2095.         JBE     C_03
  2096.         RET                                     ;  ...error  return if not
  2097.  
  2098. C_03:   SHL     AH,1                            ; Make word value
  2099.         MOV     BL,AH                           ;  ...then set up BX
  2100.         MOV     BH,0
  2101.         JMP     Word ptr CS:[BX+V_TABLE]        ;  ...vector to routines
  2102.  
  2103. CRT_0:  MOV     AL,DS:10h                       ; Set mode of CRT
  2104.         MOV     DX,3B4h                         ;  ...mono port
  2105.         AND     AL,00110000b                    ;  ...get display type
  2106.         CMP     AL,00110000b                    ;  ...equal if mono
  2107.         MOV     AL,1                            ; Assume mono display
  2108.         MOV     BL,7                            ;  ...mode is 7
  2109.         JZ      C0_01                           ;  ...Skip if mono, else CGA
  2110.         MOV     BL,[BP+2]                       ; BL = mode number (user AL)
  2111.         MOV     DL,0D4h                         ; 3D4 is CGA port
  2112.         DEC     AL
  2113.  
  2114. C0_01:  MOV     DS:63h,DX                       ; Save cur. CRT display port
  2115.         ADD     DL,4
  2116.         OUT     DX,AL                           ; Reset the video
  2117.         MOV     DS:49h,BL                       ;  ...save cur. CRT mode
  2118.         PUSH    DS
  2119.         XOR     AX,AX
  2120.         MOV     DS,AX
  2121.         LES     SI,Dword ptr DS:74h             ; SI --> INT_1D video param
  2122.         POP     DS
  2123.         MOV     BH,0
  2124.         PUSH    BX
  2125.         MOV     BL,CS:[BX+TABMUL]               ; Get BL for index into INT_1D
  2126.         ADD     SI,BX
  2127.         MOV     CX,10h                          ; Sixteen values to send
  2128.  
  2129. C0_02:  MOV     AL,ES:[SI]                      ; Value to send in SI
  2130.         CALL    SENDAX                          ;  ...send it
  2131.         INC     AH                              ;  ...bump count
  2132.         INC     SI                              ;  ...point to next
  2133.         LOOP    C0_02                           ;  ...loop until done
  2134.  
  2135.         MOV     BX,[BP+0]                       ; BX --> regen buffer
  2136.         MOV     ES,BX                           ;  ...into ES segment
  2137.         XOR     DI,DI
  2138.         CALL    MODCHK                          ; Set flags acc. to mode
  2139.         MOV     CX,2000h                        ;  ...assume CGA
  2140.         MOV     AX,0                            ;  ...and graphics
  2141.         JB      C0_04                           ;  ...do graphics fill
  2142.         JNZ     C0_03                           ;  ...Alphanumeric fill
  2143.         MOV     CX,800h                         ;  ...mono card
  2144. C0_03:  MOV     AX,7*100h+' '                   ; Word for text fill
  2145. C0_04:  REPZ    STOSW                           ;  ...fill regen buffer
  2146.  
  2147.         MOV     DX,DS:63h                       ; Get the port
  2148.         ADD     DL,4
  2149.         POP     BX
  2150.         MOV     AL,CS:[BX+MODES]                ; Load data to set for mode
  2151.         OUT     DX,AL                           ;  ...and send it
  2152.         MOV     DS:65h,AL                       ;  ...then save active data
  2153.         INC     DX
  2154.         MOV     AL,30h                          ; Assume not 640 x 200 b/w
  2155.         CMP     BL,6                            ;  ...correct?
  2156.         JNZ     C0_05
  2157.         MOV     AL,3Fh                          ; Palette for 640 x 200 b/w
  2158.  
  2159. C0_05:  MOV     DS:66h,AL                       ;  ...save palette
  2160.         OUT     DX,AL                           ;  ...send palette
  2161.         XOR     AX,AX
  2162.         MOV     DS:4Eh,AX                       ; Start at beg. of 1st page
  2163.         MOV     DS:62h,AL                       ;  ...active page=page 0
  2164.         MOV     CX,8                            ; Do 8 pages of cursor data
  2165.         MOV     DI,50h                          ; Page cursor data at 40:50
  2166.  
  2167. C0_06:  MOV     [DI],AX                         ; Cursor at upper left of page
  2168.         INC     DI                              ;  ...next page
  2169.         LOOP    C0_06
  2170.         MOV     Word ptr DS:60h,0607h           ; Cursor: Line 6 thru Line 7
  2171.         MOV     AL,CS:[BX+MAXCOL]               ; Get display width
  2172.         MOV     DS:4Ah,AX                       ;  ...save it
  2173.         AND     BL,11111110b
  2174.         MOV     AX,Word ptr CS:[BX+REGENL]      ; Get video regen length
  2175.         MOV     DS:4Ch,AX                       ;  ...save it
  2176.         RET
  2177.  
  2178. CRT_1:  MOV     CX,[BP+6]                       ; Set cursor type, from CX
  2179.         MOV     DS:60h,CX                       ;  ...save it
  2180.         MOV     AH,0Ah                          ; CRT index register 0Ah
  2181.         CALL    OT6845                          ;  ...send CH,CL to CRT reg
  2182.         RET
  2183.  
  2184. CRT_2:  MOV     BL,[BP+5]                       ; Set cursor position, page BH
  2185.         SHL     BL,1                            ;  ...(our BL)
  2186.         MOV     BH,0
  2187.         MOV     AX,[BP+8]                       ; Position in user DX (our AX)
  2188.         MOV     [BX+50h],AX                     ;  ...remember cursor position
  2189.         JMP     SETCUR                          ;  ...set 6845 cursor hardware
  2190.  
  2191. CRT_3:  MOV     BL,[BP+5]                       ; Get cursor position, page BH
  2192.         SHL     BL,1
  2193.         MOV     BH,0
  2194.         MOV     AX,[BX+50h]
  2195.         MOV     [BP+8],AX                       ;  ...return position in user DX
  2196.         MOV     AX,DS:60h                       ; Get cursor mode
  2197.         MOV     [BP+6],AX                       ;  ...return in user CX
  2198.         RET
  2199.  
  2200. PENOFF: db      3,3,5,5,3,3,3,4                 ; Light pen offset table
  2201.  
  2202. CRT_4:  MOV     DX,DS:63h                       ; Read light pen position
  2203.         ADD     DL,6
  2204.         MOV     Byte ptr [BP+3],0               ; AH=0, assume not triggered
  2205.         IN      AL,DX
  2206.         TEST    AL,00000100b
  2207.         JZ      C4_05                           ; Skip, reset if pen not set
  2208.         TEST    AL,00000010b
  2209.         JNZ     C4_01                           ; Skip if pen triggered
  2210.         RET                                     ;  ...return, do not reset
  2211.  
  2212. C4_01:  MOV     AH,10h                          ; Offset to pen port is 10h
  2213.         CALL    PENXY                           ;  ...read into CH,CL
  2214.         MOV     BL,DS:49h                       ; Get CRT mode data word
  2215.         MOV     CL,BL
  2216.         MOV     BH,0
  2217.         MOV     BL,Byte ptr CS:[BX+PENOFF]      ; Load offset for subtraction
  2218.         SUB     CX,BX
  2219.         JNS     C4_02                           ;  ...did not overflow
  2220.         XOR     AX,AX                           ; Else fudge a zero
  2221.  
  2222. C4_02:  CALL    MODCHK                          ; Set flags on display type
  2223.         JNB     C4_03                           ;  ...text mode, skip
  2224.         MOV     CH,28h
  2225.         DIV     DL
  2226.         MOV     BL,AH
  2227.         MOV     BH,0
  2228.         MOV     CL,3
  2229.         SHL     BX,CL
  2230.         MOV     CH,AL
  2231.         SHL     CH,1
  2232.         MOV     DL,AH
  2233.         MOV     DH,AL
  2234.         SHR     DH,1
  2235.         SHR     DH,1
  2236.         CMP     Byte ptr DS:49h,6               ; Mode 640 x 200 b/w?
  2237.         JNZ     C4_04                           ;  ...no, skip
  2238.         SHL     DL,1
  2239.         SHL     BX,1
  2240.         JMP     short   C4_04
  2241.  
  2242. C4_03:  DIV     Byte ptr DS:4Ah                 ; Divide by columns in screen
  2243.         XCHG    AL,AH                           ;  ...as this is text mode
  2244.         MOV     DX,AX
  2245.         MOV     CL,3
  2246.         SHL     AH,CL
  2247.         MOV     CH,AH
  2248.         MOV     BL,AL
  2249.         MOV     BH,0
  2250.         SHL     BX,CL
  2251.  
  2252. C4_04:  MOV     Byte ptr [BP+3],1               ; Return AH=1, light pen read
  2253.         MOV     [BP+8],DX                       ;  ...row, column in user DX
  2254.         MOV     [BP+4],BX                       ;  ...pixel column in user BX
  2255.         MOV     [BP+7],CH                       ;  ...raster line in user CH
  2256.  
  2257. C4_05:  MOV     DX,DS:63h                       ; Get port of active CRT card
  2258.         ADD     DX,7
  2259.         OUT     DX,AL                           ;  ...reset the light pen
  2260.         RET
  2261.  
  2262. CRT_5:  MOV     AL,[BP+2]                       ; Set active display page to AL
  2263.         MOV     DS:62h,AL                       ;  ...save new active page
  2264.         MOV     AH,0                            ;  ...clear hi order
  2265.         PUSH    AX
  2266.         MOV     BX,DS:4Ch                       ; Get size of regen. buffer
  2267.         MUL     BX                              ;  ...times number of pages
  2268.         MOV     DS:4Eh,AX                       ; Now AX = CRT offset, save
  2269.         SHR     AX,1                            ;  ...now word offset
  2270.         MOV     CX,AX                           ;  ...save a copy
  2271.         MOV     AH,0Ch                          ; CRT index register 0Ch
  2272.         CALL    OT6845                          ;  ...send CH,CL thru CRT reg
  2273.         POP     BX
  2274.         CALL    MOVCUR                          ; Save new parameters
  2275.         RET
  2276.  
  2277. CRT_6:                                          ; Scroll active page up
  2278. CRT_7:  CALL    MODCHK                          ; Scroll active page down
  2279.         JNB     SCR_01
  2280.         JMP     SCG_01                          ; Graphics scroll
  2281.  
  2282. SCR_01: CLD                                     ; Strings go upward
  2283.         CMP     Byte ptr DS:49h,2
  2284.         JB      SCR_03                          ;  ...no retrace wait needed
  2285.         CMP     Byte ptr DS:49h,3
  2286.         JA      SCR_03                          ;  ...no retrace wait needed
  2287.         MOV     DX,3DAh                         ; Else 80 x 25, do the kludge
  2288.  
  2289. SCR_02: IN      AL,DX                           ; Read CGA status register
  2290.         TEST    AL,00001000b                    ;  ...vertical retrace?
  2291.         JZ      SCR_02                          ;  ...wait until it is
  2292.         MOV     DX,3D8h                         ; Then go and
  2293.         MOV     AL,25h                          ;  ...turn the display
  2294.         OUT     DX,AL                           ;  ...off to avoid snow
  2295.  
  2296. SCR_03: MOV     AX,[BP+8]                       ; Get row,column of upper left
  2297.         PUSH    AX
  2298.         CMP     Byte ptr [BP+3],7               ; Check for scroll down
  2299.         JZ      SCR_04                          ;  ...yes, skip if so
  2300.         MOV     AX,[BP+6]                       ; Get row,column of lowr right
  2301.  
  2302. SCR_04: CALL    RC2COL                          ; Get byte offset in CRT buf
  2303.         ADD     AX,DS:4Eh                       ;  ...add  base  for CRT buf
  2304.         MOV     SI,AX
  2305.         MOV     DI,AX
  2306.         POP     DX
  2307.         SUB     DX,[BP+6]                       ; Subtract (row,col) lwr rhgt
  2308.         ADD     DX,101h                         ;  ...width of one char
  2309.         MOV     BX,DS:4Ah                       ; Get columns in display
  2310.         SHL     BX,1                            ;  ...bytes in row of display
  2311.         PUSH    DS
  2312.         MOV     AL,[BP+2]                       ; Get scroll fill character
  2313.         CALL    MAPBYT                          ;  ...calculate offset
  2314.         MOV     ES,CX                           ; CX --> byte in buffer
  2315.         MOV     DS,CX
  2316.         CMP     Byte ptr [BP+3],6               ; Scroll up?
  2317.         JZ      SCR_05                          ;  ...skip if so
  2318.         NEG     AX
  2319.         NEG     BX
  2320.         STD                                     ; Else start at top of page
  2321.  
  2322. SCR_05: MOV     CL,[BP+2]                       ; Get count of lines to scroll
  2323.         OR      CL,CL
  2324.         JZ      SCR_07                          ;  ...nothing to do
  2325.         ADD     SI,AX
  2326.         SUB     DH,[BP+2]
  2327.  
  2328. SCR_06: MOV     CH,0                            ; Clear hi order word count
  2329.         MOV     CL,DL                           ;  ...load lo order word count
  2330.         PUSH    DI
  2331.         PUSH    SI
  2332.         REPZ    MOVSW                           ; Do the scroll
  2333.         POP     SI
  2334.         POP     DI
  2335.         ADD     SI,BX                           ; Move one line in direction
  2336.         ADD     DI,BX                           ;       ""       ""
  2337.         DEC     DH                              ; One less line to scroll
  2338.         JNZ     SCR_06
  2339.         MOV     DH,[BP+2]                       ; Now get number of rows
  2340.  
  2341. SCR_07: MOV     CH,0                            ; Clear hi order word count
  2342.         MOV     AH,[BP+5]                       ;  ...get fill attribute
  2343.         MOV     AL,' '                          ;  ...fill character
  2344.  
  2345. SCR_08: MOV     CL,DL                           ; Get characters to scroll
  2346.         PUSH    DI
  2347.         REPZ    STOSW                           ;  ...store fill attr/char
  2348.         POP     DI
  2349.         ADD     DI,BX                           ; Show row was filled
  2350.         DEC     DH
  2351.         JNZ     SCR_08                          ;  ...more rows are left
  2352.         POP     DS
  2353.         CALL    MODCHK                          ; Check for monochrome card
  2354.         JZ      SCR_09                          ;  ...skip if so
  2355.         MOV     AL,DS:65h                       ; Get the mode data byte
  2356.         MOV     DX,3D8h                         ;  ...load active CRT card port
  2357.         OUT     DX,AL                           ;  ...and unblank the screen
  2358.  
  2359. SCR_09: RET
  2360.  
  2361. SCG_01: CLD                                     ; Assume GRAFIX scroll up
  2362.         MOV     AX,[BP+8]                       ; (Row,Col) of lower right
  2363.         PUSH    AX
  2364.         CMP     Byte ptr [BP+3],7               ; Scroll down?
  2365.         JZ      SCG_02                          ;  ...skip if so
  2366.         MOV     AX,[BP+6]                       ; (Row,Col) of upper left
  2367.  
  2368. SCG_02: CALL    GRAMAP                          ; Convert (Row,Col) -> Chars
  2369.         MOV     DI,AX
  2370.         POP     DX
  2371.         SUB     DX,[BP+6]                       ; Chars to copy over
  2372.         ADD     DX,101h                         ;  ...width of one char
  2373.         SHL     DH,1
  2374.         SHL     DH,1
  2375.         MOV     AL,[BP+3]                       ; Get command type
  2376.         CMP     Byte ptr DS:49h,6               ;  ...is this 640 x 200?
  2377.         JZ      SCG_03                          ;  ...skip if so
  2378.         SHL     DL,1                            ; Else bigger characters
  2379.         SHL     DI,1
  2380.         CMP     AL,7                            ; Is this scroll down?
  2381.         JNZ     SCG_03                          ;  ...skip if not so
  2382.         INC     DI
  2383.  
  2384. SCG_03: CMP     AL,7                            ; Is this scroll down?
  2385.         JNZ     SCG_04                          ;  ...skip if not so
  2386.         ADD     DI,0F0h
  2387.  
  2388. SCG_04: MOV     BL,[BP+2]                       ; Number of rows to blank
  2389.         SHL     BL,1
  2390.         SHL     BL,1
  2391.         PUSH    BX
  2392.         SUB     DH,BL                           ; Subtract from row count
  2393.         MOV     AL,50h
  2394.         MUL     BL
  2395.         MOV     BX,1FB0h
  2396.         CMP     Byte ptr [BP+3],6               ; Is this scroll up?
  2397.         JZ      SCG_05                          ;  ...skip if so
  2398.         NEG     AX                              ; Else do it
  2399.         MOV     BX,2050h
  2400.         STD                                     ; ...in reverse
  2401.  
  2402. SCG_05: MOV     SI,DI                           ; End of area
  2403.         ADD     SI,AX                           ;  ...start
  2404.         POP     AX
  2405.         OR      AL,AL
  2406.         MOV     CX,[BP+0]
  2407.         MOV     DS,CX
  2408.         MOV     ES,CX
  2409.         JZ      SCG_07                          ; No rows to scroll
  2410.         PUSH    AX
  2411.  
  2412. SCG_06: MOV     CH,0                            ; Zero hi order byte count
  2413.         MOV     CL,DL                           ;  ...bytes in row
  2414.         PUSH    SI
  2415.         PUSH    DI
  2416.         REPZ    MOVSB                           ; Copy one plane
  2417.         POP     DI
  2418.         POP     SI
  2419.         ADD     SI,2000h                        ; Load other grafix
  2420.         ADD     DI,2000h                        ;  ...video plane
  2421.         MOV     CL,DL
  2422.         PUSH    SI
  2423.         PUSH    DI
  2424.         REPZ    MOVSB                           ; Copy other plane
  2425.         POP     DI
  2426.         POP     SI
  2427.         SUB     SI,BX
  2428.         SUB     DI,BX
  2429.         DEC     DH                              ; One less row to scroll
  2430.         JNZ     SCG_06                          ;  ...loop if more to do
  2431.         POP     AX
  2432.         MOV     DH,AL                           ; Load rows to blank
  2433.  
  2434. SCG_07: MOV     AL,[BP+5]                       ; Get fill attribute
  2435.         MOV     CH,0
  2436.  
  2437. SCG_08: MOV     CL,DL                           ; Get bytes per row
  2438.         PUSH    DI
  2439.         REPZ    STOSB                           ; Load row with fill attr.
  2440.         POP     DI
  2441.         ADD     DI,2000h                        ; Do other grafix video plane
  2442.         MOV     CL,DL
  2443.         PUSH    DI
  2444.         REPZ    STOSB                           ; Load row with fill attr.
  2445.         POP     DI
  2446.         SUB     DI,BX
  2447.         DEC     DH                              ; Show one less row to blank
  2448.         JNZ     SCG_08                          ;  ...loop if more to do
  2449.         RET
  2450.  
  2451. CRT_8:                                          ; Read attribute/character
  2452. CRT_9:                                          ; Write attribute/character
  2453. CRT_10: CALL    MODCHK                          ; Write character only
  2454.         JB      CG8_01                          ;  ... graphics operation
  2455.         MOV     BL,[BP+5]                       ; Get the display page
  2456.         MOV     BH,0
  2457.         PUSH    BX
  2458.         CALL    MPRC2C                          ; Convert Row,Col,Page -> Col
  2459.         MOV     DI,AX                           ;  ...offset in DI
  2460.         POP     AX
  2461.         MUL     Word ptr DS:4Ch                 ; Page length X page number
  2462.         ADD     DI,AX                           ;  ...current char. position
  2463.         MOV     SI,DI                           ;  ...move into si
  2464.         MOV     DX,DS:63h                       ; Display port into DX
  2465.         ADD     DX,6                            ;  ...get status port
  2466.         PUSH    DS
  2467.         MOV     BX,[BP+0]                       ; BX --> regen. buffer
  2468.         MOV     DS,BX
  2469.         MOV     ES,BX
  2470.         MOV     AL,[BP+3]                       ; Get user (AH) func request
  2471.         CMP     AL,8
  2472.         JNZ     C9_01                           ;  ...skip if not read attr
  2473.  
  2474. C8_01:  IN      AL,DX                           ; Read CRT display status
  2475.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2476.         JNZ     C8_01                           ; Yes, wait for display on
  2477.         CLI                                     ;  ...no interrupts now
  2478.  
  2479. C8_02:  IN      AL,DX                           ; Read CRT display status
  2480.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2481.         JZ      C8_02                           ;  ...not yet, wait for it
  2482.  
  2483.         LODSW                                   ; Read character/attribute
  2484.         POP     DS
  2485.         MOV     [BP+2],AL                       ; Return character
  2486.         MOV     [BP+3],AH                       ;  ..and attribute
  2487.         RET
  2488.  
  2489. C9_01:  MOV     BL,[BP+2]                       ; Get char. to write
  2490.         MOV     BH,[BP+4]                       ;  ...attribute
  2491.         MOV     CX,[BP+6]                       ;  ...character count
  2492.         CMP     AL,0Ah                          ; Write char. only?
  2493.         JZ      CA_01                           ;  ...skip if so
  2494.  
  2495. C9_02:  IN      AL,DX                           ; Read CRT display status
  2496.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2497.         JNZ     C9_02                           ; Yes, wait for display on
  2498.         CLI                                     ;  ...no interrupts now
  2499.  
  2500. C9_03:  IN      AL,DX                           ; Read CRT display status
  2501.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2502.         JZ      C9_03                           ;  ...not yet, wait for it
  2503.  
  2504.         MOV     AX,BX                           ; Get char/attribute
  2505.         STOSW                                   ;  ...write it
  2506.         LOOP    C9_02                           ;  ...loop for char. count
  2507.         POP     DS
  2508.         RET
  2509.  
  2510. CA_01:  IN      AL,DX                           ; Read CRT display status
  2511.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2512.         JNZ     CA_01                           ;  ...not yet, wait for it
  2513.         CLI                                     ;  ...no interrupts now
  2514.  
  2515. CA_02:  IN      AL,DX                           ; Read CRT display status
  2516.         TEST    AL,00000001b                    ;  ...test for hor. retrace
  2517.         JZ      CA_02                           ;  ...not yet, wait for it
  2518.  
  2519.         MOV     AL,BL                           ; Get character
  2520.         STOSB                                   ;  ...write it
  2521.         INC     DI                              ;  ...skip attribute
  2522.         LOOP    CA_01                           ;  ...loop for char. count
  2523.         POP     DS
  2524.         RET
  2525.  
  2526. CG8_01: CMP     Byte ptr [BP+3],8               ; Read graphics char/attr. ?
  2527.         JNZ     CG9_01                          ;  ...no, must be write
  2528.         JMP     CGR_01                          ; Else read char/attr.
  2529.  
  2530. CG9_01: MOV     AX,DS:50h                       ; Get cursor position
  2531.         CALL    GRAMAP                          ;  ...convert (row,col) -> col
  2532.         MOV     DI,AX                           ; Save in displacement register
  2533.         PUSH    DS
  2534.         MOV     AL,[BP+2]                       ; Get character to write
  2535.         MOV     AH,0
  2536.         OR      AL,AL                           ; Is it user character set?
  2537.         JS      CG9_02                          ;  ...skip if so
  2538.         MOV     DX,CS                           ; Else use ROM character set
  2539.         MOV     SI,offset GRAFIX                ;  ...offset GRAFIX into SI
  2540.         JMP     short   CG9_03
  2541.  
  2542. CG9_02: AND     AL,7Fh                          ; Origin to zero
  2543.         XOR     BX,BX                           ;  ...then go load
  2544.         MOV     DS,BX                           ;  ...user grafix
  2545.         LDS     SI,Dword ptr DS:7Ch             ;  ...vector, offset in SI
  2546.         MOV     DX,DS                           ;  ...segment into DX
  2547.  
  2548. CG9_03: POP     DS                              ; Restore data segment
  2549.         MOV     CL,3                            ;  ...char 8 pixels wide
  2550.         SHL     AX,CL
  2551.         ADD     SI,AX                           ; Add regen. buffer base addr.
  2552.         MOV     AX,[BP+0]                       ;  ...get regen buffer addr.
  2553.         MOV     ES,AX                           ;  ...into ES
  2554.         MOV     CX,[BP+6]                       ;  ...load char. count
  2555.         CMP     Byte ptr DS:49h,6               ; Is the mode 640 x 200 b/w?
  2556.         PUSH    DS
  2557.         MOV     DS,DX
  2558.         JZ      CG8_02                          ;  ...skip if so
  2559.         SHL     DI,1
  2560.         MOV     AL,[BP+4]                       ; Get char. attribute
  2561.         AND     AX,3
  2562.         MOV     BX,5555h
  2563.         MUL     BX
  2564.         MOV     DX,AX
  2565.         MOV     BL,[BP+4]
  2566.  
  2567. CG9_04: MOV     BH,8                            ; Char 8 pixels wide
  2568.         PUSH    DI
  2569.         PUSH    SI
  2570.  
  2571. CG9_05: LODSB                                   ; Read the screen
  2572.         PUSH    CX
  2573.         PUSH    BX
  2574.         XOR     BX,BX
  2575.         MOV     CX,8
  2576.  
  2577. CG9_06: SHR     AL,1                            ; Shift bits thru byte
  2578.         RCR     BX,1
  2579.         SAR     BX,1
  2580.         LOOP    CG9_06
  2581.  
  2582.         MOV     AX,BX                           ; Result into AX
  2583.         POP     BX
  2584.         POP     CX
  2585.         AND     AX,DX
  2586.         XCHG    AH,AL
  2587.         OR      BL,BL
  2588.         JNS     CG9_07
  2589.         XOR     AX,ES:[DI]
  2590.  
  2591. CG9_07: MOV     ES:[DI],AX                      ; Write new word
  2592.         XOR     DI,2000h
  2593.         TEST    DI,2000h                        ; Is this other plane?
  2594.         JNZ     CG9_08                          ;  ...nope
  2595.         ADD     DI,50h                          ; Else advance character
  2596.  
  2597. CG9_08: DEC     BH                              ; Show another char written
  2598.         JNZ     CG9_05                          ;  ...more to go
  2599.         POP     SI
  2600.         POP     DI
  2601.         INC     DI
  2602.         INC     DI
  2603.         LOOP    CG9_04
  2604.         POP     DS
  2605.         RET
  2606.  
  2607. CG8_02: MOV     BL,[BP+4]                       ; Get display page
  2608.         MOV     DX,2000h                        ;  ...size of grafix plane
  2609.  
  2610. CG8_03: MOV     BH,8                            ; Pixel count to write
  2611.         PUSH    DI
  2612.         PUSH    SI
  2613.  
  2614. CG8_04: LODSB                                   ; Read from one plane
  2615.         OR      BL,BL                           ;  ...done both planes?
  2616.         JNS     CG8_05                          ;  ...skip if not
  2617.         XOR     AL,ES:[DI]                      ; Else load attribute
  2618.  
  2619. CG8_05: MOV     ES:[DI],AL                      ; Write out attribute
  2620.         XOR     DI,DX                           ;  ...get other plane
  2621.         TEST    DI,DX                           ; Done both planes?
  2622.         JNZ     CG8_06                          ;  ...skip if not
  2623.         ADD     DI,50h                          ; Else position for now char
  2624.  
  2625. CG8_06: DEC     BH                              ; Show row of pixels read
  2626.         JNZ     CG8_04                          ;  ...not done all of them
  2627.         POP     SI
  2628.         POP     DI
  2629.         INC     DI
  2630.         LOOP    CG8_03
  2631.         POP     DS
  2632.         RET
  2633.  
  2634. CGR_01: CLD                                     ; Increment upwards
  2635.         MOV     AX,DS:50h                       ;  ...get cursor position
  2636.         CALL    GRAMAP                          ; Convert (row,col) -> columns
  2637.         MOV     SI,AX                           ;  ...save in SI
  2638.         SUB     SP,8                            ; Grab 8 bytes temp storage
  2639.         MOV     DI,SP                           ;  ...save base in DI
  2640.         CMP     Byte ptr DS:49h,6               ; Mode 640 x 200 b/w?
  2641.         MOV     AX,[BP+0]                       ;  ...AX --> CRT regen buffer
  2642.         PUSH    DS
  2643.         PUSH    DI
  2644.         MOV     DS,AX
  2645.         JZ      CGR_06                          ; Mode is 640 x 200 b/w - skip
  2646.         MOV     DH,8                            ; Eight pixels high/char
  2647.         SHL     SI,1
  2648.         MOV     BX,2000h                        ; Bytes per video plane
  2649.  
  2650. CGR_02: MOV     AX,[SI]                         ; Read existing word
  2651.         XCHG    AH,AL
  2652.         MOV     CX,0C000h                       ; Attributes to scan for
  2653.         MOV     DL,0
  2654.  
  2655. CGR_03: TEST    AX,CX                           ; Look for attributes
  2656.         CLC
  2657.         JZ      CGR_04                          ;  ...set, skip
  2658.         STC                                     ; Else show not set
  2659.  
  2660. CGR_04: RCL     DL,1
  2661.         SHR     CX,1
  2662.         SHR     CX,1
  2663.         JNB     CGR_03                          ;  ...more shifts to go
  2664.         MOV     SS:[DI],DL
  2665.         INC     DI
  2666.         XOR     SI,BX                           ; Do other video plane
  2667.         TEST    SI,BX                           ;  ...done both planes?
  2668.         JNZ     CGR_05                          ;  ...no, skip
  2669.         ADD     SI,50h                          ; Else advance pointer
  2670.  
  2671. CGR_05: DEC     DH                              ; Show another pixel row done
  2672.         JNZ     CGR_02                          ;  ...more rows to do
  2673.         JMP     short   CGR_08
  2674.  
  2675. CGR_06: MOV     DH,4                            ; Mode 640 x 200 b/w - special
  2676.  
  2677. CGR_07: MOV     AH,[SI]                         ; Read pixels from one plane
  2678.         MOV     SS:[DI],AH                      ;  ...save on stack
  2679.         INC     DI                              ;  ...advance
  2680.         MOV     AH,[SI+2000h]                   ; Read pixels from other plane
  2681.         MOV     SS:[DI],AH                      ; Save pixels on stack
  2682.         INC     DI                              ;  ...advance
  2683.         ADD     SI,50h                          ; Total pixels in char
  2684.         DEC     DH                              ;  ...another row processed
  2685.         JNZ     CGR_07                          ;  ...more to do
  2686.  
  2687. CGR_08: MOV     DX,CS                           ; Load segment of grafix char
  2688.         MOV     DI,offset GRAFIX                ;  ...and offset
  2689.         MOV     ES,DX                           ;  ...save offset in ES
  2690.         MOV     DX,SS
  2691.         MOV     DS,DX
  2692.         POP     SI
  2693.         MOV     AL,0
  2694.  
  2695. CGR_09: MOV     DX,80h                          ; Number of char. in grafix set
  2696.  
  2697. CGR_10: PUSH    SI
  2698.         PUSH    DI
  2699.         MOV     CX,8                            ; Bytes to compare for char
  2700.         REPZ    CMPSB                           ;  ...do compare
  2701.         POP     DI
  2702.         POP     SI
  2703.         JZ      CGR_11                          ; Found grafix character
  2704.         INC     AL                              ;  ...else show another char
  2705.         ADD     DI,8                            ;  ...advance one row
  2706.         DEC     DX                              ;  ...one less char  to scan
  2707.         JNZ     CGR_10                          ; Loop if more char left
  2708.  
  2709.         OR      AL,AL                           ; User grafix character set?
  2710.         JZ      CGR_11                          ;  ...no, not found
  2711.         XOR     BX,BX
  2712.         MOV     DS,BX
  2713.         LES     DI,Dword ptr DS:7Ch             ; Else load user grafix char
  2714.         MOV     BX,ES
  2715.         OR      BX,DI
  2716.         JZ      CGR_11                          ;  ...not found
  2717.         JMP     short   CGR_09                  ; Try using user grafix char
  2718.  
  2719. CGR_11: MOV     [BP+2],AL                       ; Return char in user AL
  2720.         POP     DS
  2721.         ADD     SP,8                            ;  ...return temp storage
  2722.         RET
  2723.  
  2724. CRT_11: MOV     DX,DS:63h                       ; Set color, get CGA card port
  2725.         ADD     DX,5                            ;  ...color select register
  2726.         MOV     AL,DS:66h                       ; Get CRT palette
  2727.         MOV     AH,[BP+5]                       ; ...new palette ID, user BH
  2728.         OR      AH,AH
  2729.         MOV     AH,[BP+4]                       ; ...new palette color, user BL
  2730.         JNZ     C_PAL1                          ; Palette ID specified, skip
  2731.         AND     AL,0E0h
  2732.         AND     AH,1Fh                          ; Null ID = ID 01Fh
  2733.         OR      AL,AH                           ;  ...set in color
  2734.         JMP     short   C_PAL2
  2735.  
  2736. C_PAL1: AND     AL,0DFh
  2737.         TEST    AH,1
  2738.         JZ      C_PAL2
  2739.         OR      AL,20h
  2740.  
  2741. C_PAL2: MOV     DS:66h,AL                       ; Save new palette
  2742.         OUT     DX,AL                           ;  ...tell CGA about it
  2743.         RET
  2744.  
  2745. CRT_12: MOV     AX,[BP+0]                       ; Write pixel
  2746.         MOV     ES,AX
  2747.         MOV     DX,[BP+8]                       ; Load row from user DX
  2748.         MOV     CX,[BP+6]                       ;  ... col from user CX
  2749.         CALL    LOCDOT                          ; Find dot offset
  2750.         JNZ     WD_01                           ; ...valid
  2751.         MOV     AL,[BP+2]                       ; Load user color
  2752.         MOV     BL,AL
  2753.         AND     AL,1
  2754.         ROR     AL,1
  2755.         MOV     AH,7Fh
  2756.         JMP     short   WD_02
  2757.  
  2758. WD_01:  SHL     CL,1
  2759.         MOV     AL,[BP+2]
  2760.         MOV     BL,AL
  2761.         AND     AL,3
  2762.         ROR     AL,1
  2763.         ROR     AL,1
  2764.         MOV     AH,3Fh
  2765.  
  2766. WD_02:  ROR     AH,CL
  2767.         SHR     AL,CL
  2768.         MOV     CL,ES:[SI]                      ; Read the char with the dot
  2769.         OR      BL,BL
  2770.         JNS     WD_03
  2771.         XOR     CL,AL                           ; Exclusive or existing color
  2772.         JMP     short   WD_04
  2773.  
  2774. WD_03:  AND     CL,AH                           ; Set new color for dot
  2775.         OR      CL,AL
  2776.  
  2777. WD_04:  MOV     ES:[SI],CL                      ; Write out char with the dot
  2778.         RET
  2779.  
  2780. CRT_13: MOV     AX,[BP+0]                       ; AX --> video regen buffer
  2781.         MOV     ES,AX                           ;  ...into ES segment
  2782.         MOV     DX,[BP+8]                       ; Load row from user DX
  2783.         MOV     CX,[BP+6]                       ;  ... col from user CX
  2784.         CALL    LOCDOT                          ; Calculate dot offset
  2785.         MOV     AL,ES:[SI]                      ;  ...read dot
  2786.         JNZ     RD_01                           ;  ...was there
  2787.         SHL     AL,CL
  2788.         ROL     AL,1
  2789.         AND     AL,1
  2790.         JMP     short   RD_02
  2791.  
  2792. RD_01:  SHL     CL,1                            ; Calculate offset in char
  2793.         SHL     AL,CL
  2794.         ROL     AL,1
  2795.         ROL     AL,1
  2796.         AND     AL,3
  2797.  
  2798. RD_02:  MOV     [BP+2],AL                       ; Return dot pos in user AL
  2799.         RET
  2800.  
  2801. CRT_14: MOV     BL,DS:62h                       ; Get active video page (0-7)
  2802.         SHL     BL,1                            ;  ...as word index
  2803.         MOV     BH,0                            ;  ...clear hi order
  2804.         MOV     DX,[BX+50h]                     ; Index into cursor position
  2805.  
  2806.         MOV     AL,[BP+2]                       ; Get char. to write
  2807.         CMP     AL,8                            ;  ...back space?
  2808.         JZ      TTY_BS                          ;  ...skip if so
  2809.         CMP     AL,LF                           ; Is it a carriage return
  2810.         JZ      TTY_LF                          ;  ...skip if so
  2811.         CMP     AL,7                            ; Print a bell?
  2812.         JZ      BLIP                            ;  ...do beep
  2813.         CMP     AL,CR                           ; Is it a line feed?
  2814.         JZ      TTY_CR                          ;  ...skip if so
  2815.         MOV     BL,[BP+4]                       ; Else write at cur pos
  2816.         MOV     AH,0Ah
  2817.         MOV     CX,1                            ;  ...one time
  2818.         INT     10h
  2819.         INC     DL                              ; Advance cursor
  2820.         CMP     DL,DS:4Ah                       ;  ...check for line overflow
  2821.         JNZ     TTYPOS
  2822.         MOV     DL,0                            ; Overflowed, then fake
  2823.         JMP     short   TTY_LF                  ;  ...new line
  2824.  
  2825. TTY_BS: CMP     DL,0                            ; At start of line?
  2826.         JZ      TTYPOS                          ;  ...skip if so
  2827.         DEC     DL                              ; Else back up
  2828.         JMP     short   TTYPOS                  ;  ...join common code
  2829.  
  2830. BLIP:   MOV     BL,2                            ; Do a short
  2831.         CALL    BEEP                            ;  ...beep
  2832.         RET
  2833.  
  2834. TTY_CR: MOV     DL,0                            ; Position to start of line
  2835. ;       JMP     short   TTYPOS
  2836.  
  2837. TTYPOS: MOV     BL,DS:62h                       ; Get active video page (0-7)
  2838.         SHL     BL,1                            ;  ...as word index
  2839.         MOV     BH,0                            ;  ...clear hi order
  2840.         MOV     [BX+50h],DX                     ; Remember the cursor position
  2841.         JMP     SETCUR                          ;  ...set 6845 cursor hardware
  2842.  
  2843. TTY_LF: CMP     DH,18h                          ; Done all 24 lines on page?
  2844.         JZ      TTY_L1                          ;  ...yes, scroll
  2845.         INC     DH                              ; Else advance line
  2846.         JNZ     TTYPOS
  2847.  
  2848. TTY_L1: MOV     AH,2                            ; Position cursor at line start
  2849.         INT     10h
  2850.         CALL    MODCHK                          ; Is this text mode?
  2851.         MOV     BH,0
  2852.         JB      TTY_L2                          ; Skip if text mode
  2853.         MOV     AH,8
  2854.         INT     10h                             ;  ...else read attribute
  2855.         MOV     BH,AH
  2856.  
  2857. TTY_L2: MOV     AH,6                            ; Now prepare to
  2858.         MOV     AL,1                            ;  ...scroll
  2859.         XOR     CX,CX                           ;  ...the
  2860.         MOV     DH,18h                          ;  ...page
  2861.         MOV     DL,DS:4Ah                       ;  ...up
  2862.         DEC     DL
  2863.         INT     10h
  2864.         RET
  2865.  
  2866. CRT_15: MOV     AL,DS:4Ah                       ; Get current video state
  2867.         MOV     [BP+3],AL                       ;  ...columns
  2868.         MOV     AL,DS:49h
  2869.         MOV     [BP+2],AL                       ;  ...mode
  2870.         MOV     AL,DS:62h
  2871.         MOV     [BP+5],AL                       ;  ...page
  2872.         RET
  2873.  
  2874. MODCHK: PUSH    AX                              ; Set flags acc. to cur. mode
  2875.         MOV     AL,DS:49h                       ;  ...get mode
  2876.         CMP     AL,7                            ;  ...EQU if mono
  2877.         JZ      MODCH1
  2878.         CMP     AL,4
  2879.         CMC
  2880.         JNB     MODCH1                          ;  ...carry set on graphix
  2881.         SBB     AL,AL
  2882.         STC
  2883.  
  2884. MODCH1: POP     AX
  2885.         RET
  2886.  
  2887. LOCDOT: MOV     AL,50h                          ; Dots in char. position
  2888.         XOR     SI,SI
  2889.         SHR     DL,1                            ; Two bytes/char. position
  2890.         JNB     LOCDO1                          ;  ...not overflow
  2891.         MOV     SI,2000h                        ; Else on other video plane
  2892.  
  2893. LOCDO1: MUL     DL                              ; Multiply position by row
  2894.         ADD     SI,AX                           ;  ...add in column position
  2895.         MOV     DX,CX                           ; Copy column position
  2896.         MOV     CX,302h                         ;  ...regular char size
  2897.         CMP     Byte ptr DS:49h,6               ; Mode 640 x 200, b/w?
  2898.         PUSHF
  2899.         JNZ     LOCDO2                          ;  ...skip if not
  2900.         MOV     CX,703h                         ; Else special char. size
  2901.  
  2902. LOCDO2: AND     CH,DL
  2903.         SHR     DX,CL
  2904.         ADD     SI,DX
  2905.         XCHG    CL,CH
  2906.         POPF
  2907.         RET
  2908.  
  2909. PENXY:  CALL    PENXY1                          ; Read light pen position HI
  2910.         MOV     CH,AL                           ;  ...save in CH
  2911.         INC     AH
  2912.         CALL    PENXY1                          ; Read light pen position LO
  2913.         MOV     CL,AL                           ;  ...save in CL
  2914.         RET
  2915.  
  2916. PENXY1: PUSH    DX                              ; Read CRT register offset AL
  2917.         MOV     DX,DS:63h                       ;  ...get active CRT port
  2918.         XCHG    AL,AH
  2919.         OUT     DX,AL                           ; Send initialization byte
  2920.         INC     DL                              ;  ...increment
  2921.         IN      AL,DX                           ; Read pen position byte back
  2922.         POP     DX
  2923.         RET
  2924.  
  2925. MPRC2C: MOV     BH,0                            ; Convert Row,Col,Page -> Col
  2926.         SHL     BX,1                            ;  ...two bytes/column
  2927.         MOV     AX,[BX+50h]                     ; Get page number in AX
  2928.                                                 ;  ...join common code
  2929. RC2COL: PUSH    BX                              ; Map (AH=row,AL=COL) to COL
  2930.         MOV     BL,AL
  2931.         MOV     AL,AH
  2932.         MUL     Byte ptr DS:4Ah                 ; Multiply ROW x (Row/Column)
  2933.         MOV     BH,0
  2934.         ADD     AX,BX                           ;  ...add in existing COL
  2935.         SHL     AX,1                            ;  ...times 2 cause 2 bytes/col
  2936.         POP     BX
  2937.         RET
  2938.  
  2939. GRAMAP: PUSH    BX                              ; Convert (row,col) -> col
  2940.         MOV     BL,AL                           ;  ...save column
  2941.         MOV     AL,AH                           ;  ...get row
  2942.         MUL     Byte ptr DS:4Ah                 ; Multiply by columns/row
  2943.         SHL     AX,1
  2944.         SHL     AX,1
  2945.         MOV     BH,0
  2946.         ADD     AX,BX                           ; Add in columns
  2947.         POP     BX
  2948.         RET
  2949.  
  2950. SETCUR: SHR     BL,1                            ; Sets 6845 cursor position
  2951.         CMP     DS:62h,BL                       ;  ...is this page visible?
  2952.         JNZ     SEND01                          ; No, do nothing in hardware
  2953.  
  2954. MOVCUR: CALL    MPRC2C                          ; Map row,col,page to col
  2955.         ADD     AX,DS:4Eh                       ;  + byte offset, regen reg.
  2956.         SHR     AX,1
  2957.         MOV     CX,AX
  2958.         MOV     AH,0Eh                          ; Tell 6845 video controller
  2959.                                                 ;  ...to position the cursor
  2960.  
  2961. OT6845: MOV     AL,CH                           ; Send CH,CL thru CRT reg AH
  2962.         CALL    SENDAX                          ;  ...send CH
  2963.         INC     AH                              ;  ...increment
  2964.         MOV     AL,CL                           ;  ...send CL
  2965.  
  2966. SENDAX: PUSH    DX
  2967.         MOV     DX,DS:63h                       ; Load active video port
  2968.         XCHG    AL,AH
  2969.         OUT     DX,AL                           ; Send hi order
  2970.         XCHG    AL,AH
  2971.         INC     DL
  2972.         OUT     DX,AL                           ;  ... lo order
  2973.         POP     DX
  2974.  
  2975. SEND01: RET
  2976.  
  2977.         ENTRY   0F841h                          ; IBM entry for memory size
  2978.  
  2979. INT_12: STI                                     ; Kbytes of memory present
  2980.         PUSH    DS
  2981.         MOV     AX,40h
  2982.         MOV     DS,AX
  2983.         MOV     AX,DS:13h                       ; AX = memory size, kilobytes
  2984.         POP     DS
  2985.         IRET
  2986.  
  2987.         ENTRY   0F84Dh                          ; IBM entry for equipment check
  2988.  
  2989. INT_11: STI                                     ; Equipment present
  2990.         PUSH    DS
  2991.         MOV     AX,40h
  2992.         MOV     DS,AX
  2993.         MOV     AX,DS:10h                       ; AX = equipment byte contents
  2994.         POP     DS
  2995.         IRET
  2996.  
  2997.         ENTRY   0F859h                          ; IBM entry for cassette int.
  2998.  
  2999. INT_15: STC                                     ; Cassette service (error ret)
  3000.         MOV     AH,86h
  3001.         RETF    2
  3002.  
  3003.         ENTRY   0F85Fh                          ; IBM non-maskable int. entry
  3004.  
  3005. INT_2:  PUSH    AX                              ; Non-maskable interrupt
  3006.         IN      AL,62h
  3007.         TEST    AL,11000000b                    ; Get cause of interrupt
  3008.         JNZ     PAR_01                          ;  ...parity error
  3009.         JMP     PAR_07                          ;  ...math coprocessor (?)
  3010.  
  3011. PAR_01: PUSH    BX                              ; Parity error bomb
  3012.         PUSH    CX
  3013.         PUSH    DX
  3014.         PUSH    SI
  3015.         PUSH    DI
  3016.         PUSH    BP
  3017.         PUSH    DS
  3018.         PUSH    ES
  3019.         MOV     AX,40h                          ; Load data segment
  3020.         MOV     DS,AX
  3021.         CALL    V_INIT                          ;  ...clear/init screen
  3022.         PUSH    DS
  3023.         PUSH    CS                              ; Point DS at ROM
  3024.         POP     DS
  3025.         MOV     SI,offset BOMB_1                ; SI --> Parity message
  3026.         CALL    PRINT                           ;  ...print
  3027.         POP     DS                              ;  ...restore DS
  3028.         MOV     AX,11h                          ; Back cursor over ? marks
  3029.         CALL    LOCATE                          ;  ...with call
  3030.         MOV     AL,0
  3031.         OUT     0A0h,AL                         ;  ...disable NMI interrupts
  3032.         MOV     DX,61h
  3033.         IN      AL,DX                           ; Get machine flags
  3034.         OR      AL,00110000b                    ;  ...disable parity int.
  3035.         OUT     DX,AL                           ; Put out new flags
  3036.         AND     AL,11001111b                    ;  ...enable  parity int.
  3037.         OUT     DX,AL                           ; Put out new flags
  3038.         MOV     CL,6
  3039.         MOV     BX,DS:13h                       ; Get memory size (K bytes)
  3040.         SHL     BX,CL
  3041.         INC     DX                              ;  ...now paragraphs
  3042.         XOR     AX,AX
  3043.         MOV     DS,AX
  3044.  
  3045. PAR_02: MOV     CX,10h                          ; Iterations to check
  3046.         XOR     SI,SI
  3047.  
  3048. PAR_03: MOV     AH,[SI]                         ; Read the byte (dummy)
  3049.         IN      AL,DX                           ;  ...and read status
  3050.         TEST    AL,11000000b                    ;  ...to see what happened
  3051.         JNZ     PAR_04                          ; Read caused parity error
  3052.         INC     SI                              ;  ...else advance pointer
  3053.         LOOP    PAR_03                          ;  ...and try next byte
  3054.  
  3055.         MOV     AX,DS
  3056.         INC     AX                              ;  ...next paragraph
  3057.         MOV     DS,AX
  3058.         CMP     AX,BX
  3059.         JNZ     PAR_02                          ; More paragraphs to check
  3060.         JMP     short   PAR_05                  ;  ...else flakey error
  3061.  
  3062. PAR_04: MOV     [SI],AH                         ; Save offset in paragraph
  3063.         MOV     AX,DS
  3064.         CALL    BIGNUM                          ; Print segment
  3065.         MOV     AX,SI
  3066.         CALL    DIGIT                           ; Print offset
  3067.  
  3068. PAR_05: MOV     AX,16h                          ; Where to position cursor
  3069.         CALL    LOCATE                          ; ...position cursor
  3070.         PUSH    DS
  3071.         PUSH    CS
  3072.         POP     DS
  3073.         MOV     SI,offset BOMB_2                ; Continue ?
  3074.         CALL    PRINT                           ;  ...ask the user
  3075.         POP     DS
  3076.         IN      AL,21h                          ; Get interrupt masks
  3077.         PUSH    AX                              ;  ...save them
  3078.         MOV     AL,11111100b
  3079.         OUT     21h,AL                          ; Disable all but keyboard
  3080.         STI                                     ;  ...enable interrupt system
  3081.         CALL    GETCH                           ; Get keyboard character
  3082.         PUSH    AX                              ;  ...save it
  3083.         CALL    OUTCHR                          ; Print ascii character
  3084.         POP     AX                              ;  ...restore
  3085.         CMP     AL,'Y'                          ; User wants to continue
  3086.         JZ      PAR_06                          ;  ...stupid answer
  3087.         CMP     AL,'y'                          ; Look for little case "y"
  3088.         JZ      PAR_06                          ;  ...stupid answer
  3089.         JMP     COLD                            ; Retry on cold reboot
  3090.  
  3091. PAR_06: CALL    BLANK                           ; Clear display
  3092.         POP     AX
  3093.         OUT     21h,AL                          ; Restore interrupt system state
  3094.         MOV     DX,61h                          ; Dismiss the NMI interrupt
  3095.         IN      AL,DX                           ;   ...read in machine flags
  3096.         OR      AL,00110000b
  3097.         OUT     DX,AL                           ; Write out, parity disabled
  3098.         AND     AL,11001111b                    ;  ...clears parity error
  3099.         OUT     DX,AL                           ; Write out, parity enabled
  3100.         MOV     AL,80h
  3101.         OUT     0A0h,AL                         ; Enable NMI interrupts
  3102.         POP     ES
  3103.         POP     DS
  3104.         POP     BP
  3105.         POP     DI
  3106.         POP     SI
  3107.         POP     DX
  3108.         POP     CX
  3109.         POP     BX
  3110.  
  3111. PAR_07: POP     AX
  3112.         IRET
  3113.  
  3114. BOMB_1  db      'Parity error at: ?????',0
  3115. BOMB_2  db      ' Cont?',0
  3116.  
  3117. NUMBER: PUSH    AX                              ; Save number
  3118.         MOV     CL,4
  3119.         SHR     AL,CL
  3120.         CALL    DIGIT                           ; Out first  digit
  3121.         POP     AX
  3122.         CALL    DIGIT                           ; Out second digit
  3123.         RET
  3124.  
  3125. BIGNUM: PUSH    AX                              ; Unsigned word
  3126.         MOV     AL,AH
  3127.         CALL    NUMBER
  3128.         POP     AX
  3129.         CALL    NUMBER
  3130.         RET
  3131.  
  3132. OUTCHR: PUSH    BX
  3133.         PUSH    AX
  3134.         MOV     AH,0Eh                          ; Teletype print service
  3135.         MOV     BL,7                            ;  ...normal intensity
  3136.         INT     10h
  3137.         POP     AX
  3138.         POP     BX
  3139.         RET
  3140.  
  3141. DIGIT:  PUSH    AX                              ; Print hex digit in AL
  3142.         AND     AL,0Fh
  3143.         CMP     AL,9
  3144.         JBE     D_01
  3145.         ADD     AL,'A'-'9'-1
  3146.  
  3147. D_01:   ADD     AL,'0'                          ; Make ascii digit
  3148.         CALL    OUTCHR                          ; ...print it
  3149.         POP     AX
  3150.         RET
  3151.  
  3152.         MOV     AL,CR                           ; Print carriage return
  3153.         CALL    OUTCHR                          ;  ...on screen
  3154.         MOV     AL,LF                           ; Print line feed
  3155.         CALL    OUTCHR                          ;  ...on screen
  3156.         RET
  3157.  
  3158. GETCH:  MOV     AH,0                            ; Read keyboard key
  3159.         INT     16h
  3160.         RET
  3161.  
  3162. PRINT:  LODSB                                   ; Print zero terminated string
  3163.         OR      AL,AL
  3164.         JNZ     PRINT1                          ;  ...not terminator in AX
  3165.         RET
  3166.  
  3167. PRINT1: CALL    OUTCHR                          ; Print character in AX
  3168.         JMP     PRINT                           ;  ...back for more
  3169.  
  3170. BEEP:   PUSH    AX
  3171.         PUSH    CX
  3172.         MOV     AL,10110110b                    ; Timer ic 8253 square waves
  3173.         OUT     43h,AL                          ;  ...channel 2, speaker
  3174.         MOV     AX,528h                         ; Get countdown constant word
  3175.         OUT     42h,AL                          ;  ...send lo order
  3176.         MOV     AL,AH                           ;  ...load hi order
  3177.         OUT     42h,AL                          ;  ...send hi order
  3178.         IN      AL,61h                          ; Read ic 8255 machine status
  3179.         PUSH    AX
  3180.         OR      AL,00000011b
  3181.         OUT     61h,AL                          ; Turn speaker on
  3182.         XOR     CX,CX
  3183.  
  3184. BEEP_1: LOOP    BEEP_1
  3185.         DEC     BL
  3186.         JNZ     BEEP_1
  3187.         POP     AX
  3188.         OUT     61h,AL                          ; Turn speaker off
  3189.         POP     CX
  3190.         POP     AX
  3191.         RET
  3192.  
  3193. V_INIT: MOV     AH,DS:10h                       ; Get equipment byte
  3194.         AND     AH,00110000b                    ;  ...extract CRT
  3195.         MOV     AL,0                            ;  ...null lo
  3196.         CMP     AH,00110000b                    ; Monochrome?
  3197.         JZ      LF9D9                           ;  ...yes
  3198.         MOV     AL,1                            ; CGA 40 x 25?
  3199.         CMP     AH,00010000b                    ;  ...yes
  3200.         JZ      LF9D9                           ; CGA 80 x 25?
  3201.         MOV     AL,3                            ;  ...yes
  3202.  
  3203. LF9D9:  MOV     AH,0                            ; Setup subfunction
  3204.         INT     10h                             ;  ...to video
  3205.         RET
  3206.  
  3207. BLANK:  MOV     DX,184Fh                        ; Lower right corner of scroll
  3208.         XOR     CX,CX                           ; Upper left  corner of scroll
  3209.         MOV     AX,600h                         ; Blank entire window
  3210.         MOV     BH,7                            ; Set regular cursor
  3211.         INT     10h                             ; Call video service scroll
  3212.         MOV     AH,2                            ; Set cursor position
  3213.         XOR     DX,DX                           ;  ...upper left corner
  3214.         MOV     BH,0                            ;  ...page 0
  3215.         INT     10h                             ;  ...call video service
  3216.         RET
  3217.  
  3218. LOCATE: PUSH    DX
  3219.         PUSH    BX
  3220.         MOV     DX,AX                           ; Get position for cursor
  3221.         MOV     AH,2
  3222.         MOV     BH,0                            ;  ...page 0
  3223.         INT     10h
  3224.         POP     BX
  3225.         POP     DX
  3226.         RET
  3227.  
  3228. CHKSUM: MOV     CX,2000h                        ; Bytes in 2764 eprom
  3229.  
  3230. CHK_01: MOV     AL,0                            ;  ...zero checksum
  3231.  
  3232. ADDBYT: ADD     AL,[BX]                         ; Add byte to checksum
  3233.         INC     BX                              ;  ...BX --> next byte
  3234.         LOOP    ADDBYT                          ;  ...loop until done
  3235.         OR      AL,AL                           ; Set condition codes
  3236.         RET                                     ;  ...and return
  3237.  
  3238. MEMTST: MOV     BX,0400h                        ; Load bytes to test
  3239.         MOV     AL,55h
  3240. ;
  3241. PAT_1:  XOR     DI,DI                           ; Pattern #1, 55h bytes
  3242.         MOV     CX,BX
  3243.         REPZ    STOSB                           ; Fill memory, pattern #1
  3244.         XOR     DI,DI
  3245.         MOV     CX,BX
  3246.         REPZ    SCASB                           ; Scan memory for NOT pattern #1
  3247.         JCXZ    PAT_2
  3248.         STC                                     ;  ...flunked
  3249.         RET
  3250.  
  3251. PAT_2:  XOR     DI,DI                           ; Pattern #2 - 0AAh bytes
  3252.         MOV     CX,BX
  3253.         NOT     AL
  3254.         REPZ    STOSB                           ; Fill memory, pattern #2
  3255.         XOR     DI,DI
  3256.         MOV     CX,BX
  3257.         REPZ    SCASB                           ; Scan memory for NOT pattern #2
  3258.         JCXZ    PAT_3
  3259.         STC                                     ;  ...flunked
  3260.         RET
  3261.  
  3262. PAT_3:  XOR     DI,DI                           ; Pattern #3 - 01h bytes
  3263.         MOV     CX,BX
  3264.         MOV     AL,1
  3265.         REPZ    STOSB                           ; Fill memory, pattern #3
  3266.         XOR     DI,DI
  3267.         MOV     CX,BX
  3268.         REPZ    SCASB                           ; Scan memory for NOT pattern #3
  3269.         JCXZ    PAT_4
  3270.         STC                                     ;  ...flunked
  3271.         RET
  3272.  
  3273. PAT_4:  XOR     DI,DI                           ; Pattern #4 - 0h bytes
  3274.         MOV     CX,BX
  3275.         DEC     AL
  3276.         REPZ    STOSB                           ; Fill memory, pattern #4
  3277.         XOR     DI,DI
  3278.         MOV     CX,BX
  3279.         REPZ    SCASB                           ; Scan memory for NOT pattern #4
  3280.         JCXZ    LFA59
  3281.         STC                                     ;  ...flunked
  3282.         RET
  3283.  
  3284. LFA59:  MOV     AX,ES
  3285.         ADD     AX,40h                          ; Add 40h to segment number
  3286.         MOV     ES,AX
  3287.         RET                                     ;  ...passed
  3288.  
  3289.         ENTRY   0FA6Eh                          ; IBM graphics char set entry
  3290.  
  3291. GRAFIX  db      000h,000h,000h,000h             ; Graphics character set
  3292.         db      000h,000h,000h,000h
  3293.         db      07Eh,081h,0A5h,081h
  3294.         db      0BDh,099h,081h,07Eh
  3295.         db      07Eh,0FFh,0DBh,0FFh
  3296.         db      0C3h,0E7h,0FFh,07Eh
  3297.         db      06Ch,0FEh,0FEh,0FEh
  3298.         db      07Ch,038h,010h,000h
  3299.  
  3300.         db      010h,038h,07Ch,0FEh
  3301.         db      07Ch,038h,010h,000h
  3302.         db      038h,07Ch,038h,0FEh
  3303.         db      0FEh,07Ch,038h,07Ch
  3304.         db      010h,010h,038h,07Ch
  3305.         db      0FEh,07Ch,038h,07Ch
  3306.         db      000h,000h,018h,03Ch
  3307.         db      03Ch,018h,000h,000h
  3308.  
  3309.         db      0FFh,0FFh,0E7h,0C3h
  3310.         db      0C3h,0E7h,0FFh,0FFh
  3311.         db      000h,03Ch,066h,042h
  3312.         db      042h,066h,03Ch,000h
  3313.         db      0FFh,0C3h,099h,0BDh
  3314.         db      0BDh,099h,0C3h,0FFh
  3315.         db      00Fh,007h,00Fh,07Dh
  3316.         db      0CCh,0CCh,0CCh,078h
  3317.  
  3318.         db      03Ch,066h,066h,066h
  3319.         db      03Ch,018h,07Eh,018h
  3320.         db      03Fh,033h,03Fh,030h
  3321.         db      030h,070h,0F0h,0E0h
  3322.         db      07Fh,063h,07Fh,063h
  3323.         db      063h,067h,0E6h,0C0h
  3324.         db      099h,05Ah,03Ch,0E7h
  3325.         db      0E7h,03Ch,05Ah,099h
  3326.  
  3327.         db      080h,0E0h,0F8h,0FEh
  3328.         db      0F8h,0E0h,080h,000h
  3329.         db      002h,00Eh,03Eh,0FEh
  3330.         db      03Eh,00Eh,002h,000h
  3331.         db      018h,03Ch,07Eh,018h
  3332.         db      018h,07Eh,03Ch,018h
  3333.         db      066h,066h,066h,066h
  3334.         db      066h,000h,066h,000h
  3335.  
  3336.         db      07Fh,0DBh,0DBh,07Bh
  3337.         db      01Bh,01Bh,01Bh,000h
  3338.         db      03Eh,063h,038h,06Ch
  3339.         db      06Ch,038h,0CCh,078h
  3340.         db      000h,000h,000h,000h
  3341.         db      07Eh,07Eh,07Eh,000h
  3342.         db      018h,03Ch,07Eh,018h
  3343.         db      07Eh,03Ch,018h,0FFh
  3344.  
  3345.         db      018h,03Ch,07Eh,018h
  3346.         db      018h,018h,018h,000h
  3347.         db      018h,018h,018h,018h
  3348.         db      07Eh,03Ch,018h,000h
  3349.         db      000h,018h,00Ch,0FEh
  3350.         db      00Ch,018h,000h,000h
  3351.         db      000h,030h,060h,0FEh
  3352.         db      060h,030h,000h,000h
  3353.  
  3354.         db      000h,000h,0C0h,0C0h
  3355.         db      0C0h,0FEh,000h,000h
  3356.         db      000h,024h,066h,0FFh
  3357.         db      066h,024h,000h,000h
  3358.         db      000h,018h,03Ch,07Eh
  3359.         db      0FFh,0FFh,000h,000h
  3360.         db      000h,0FFh,0FFh,07Eh
  3361.         db      03Ch,018h,000h,000h
  3362.  
  3363.         db      000h,000h,000h,000h
  3364.         db      000h,000h,000h,000h
  3365.         db      030h,078h,078h,030h
  3366.         db      030h,000h,030h,000h
  3367.         db      06Ch,06Ch,06Ch,000h
  3368.         db      000h,000h,000h,000h
  3369.         db      06Ch,06Ch,0FEh,06Ch
  3370.         db      0FEh,06Ch,06Ch,000h
  3371.  
  3372.         db      030h,07Ch,0C0h,078h
  3373.         db      00Ch,0F8h,030h,000h
  3374.         db      000h,0C6h,0CCh,018h
  3375.         db      030h,066h,0C6h,000h
  3376.         db      038h,06Ch,038h,076h
  3377.         db      0DCh,0CCh,076h,000h
  3378.         db      060h,060h,0C0h,000h
  3379.         db      000h,000h,000h,000h
  3380.  
  3381.         db      018h,030h,060h,060h
  3382.         db      060h,030h,018h,000h
  3383.         db      060h,030h,018h,018h
  3384.         db      018h,030h,060h,000h
  3385.         db      000h,066h,03Ch,0FFh
  3386.         db      03Ch,066h,000h,000h
  3387.         db      000h,030h,030h,0FCh
  3388.         db      030h,030h,000h,000h
  3389.  
  3390.         db      000h,000h,000h,000h
  3391.         db      000h,030h,030h,060h
  3392.         db      000h,000h,000h,0FCh
  3393.         db      000h,000h,000h,000h
  3394.         db      000h,000h,000h,000h
  3395.         db      000h,030h,030h,000h
  3396.         db      006h,00Ch,018h,030h
  3397.         db      060h,0C0h,080h,000h
  3398.  
  3399.         db      07Ch,0C6h,0CEh,0DEh
  3400.         db      0F6h,0E6h,07Ch,000h
  3401.         db      030h,070h,030h,030h
  3402.         db      030h,030h,0FCh,000h
  3403.         db      078h,0CCh,00Ch,038h
  3404.         db      060h,0CCh,0FCh,000h
  3405.         db      078h,0CCh,00Ch,038h
  3406.         db      00Ch,0CCh,078h,000h
  3407.  
  3408.         db      01Ch,03Ch,06Ch,0CCh
  3409.         db      0FEh,00Ch,01Eh,000h
  3410.         db      0FCh,0C0h,0F8h,00Ch
  3411.         db      00Ch,0CCh,078h,000h
  3412.         db      038h,060h,0C0h,0F8h
  3413.         db      0CCh,0CCh,078h,000h
  3414.         db      0FCh,0CCh,00Ch,018h
  3415.         db      030h,030h,030h,000h
  3416.  
  3417.         db      078h,0CCh,0CCh,078h
  3418.         db      0CCh,0CCh,078h,000h
  3419.         db      078h,0CCh,0CCh,07Ch
  3420.         db      00Ch,018h,070h,000h
  3421.         db      000h,030h,030h,000h
  3422.         db      000h,030h,030h,000h
  3423.         db      000h,030h,030h,000h
  3424.         db      000h,030h,030h,060h
  3425.  
  3426.         db      018h,030h,060h,0C0h
  3427.         db      060h,030h,018h,000h
  3428.         db      000h,000h,0FCh,000h
  3429.         db      000h,0FCh,000h,000h
  3430.         db      060h,030h,018h,00Ch
  3431.         db      018h,030h,060h,000h
  3432.         db      078h,0CCh,00Ch,018h
  3433.         db      030h,000h,030h,000h
  3434.  
  3435.         db      07Ch,0C6h,0DEh,0DEh
  3436.         db      0DEh,0C0h,078h,000h
  3437.         db      030h,078h,0CCh,0CCh
  3438.         db      0FCh,0CCh,0CCh,000h
  3439.         db      0FCh,066h,066h,07Ch
  3440.         db      066h,066h,0FCh,000h
  3441.         db      03Ch,066h,0C0h,0C0h
  3442.         db      0C0h,066h,03Ch,000h
  3443.  
  3444.         db      0F8h,06Ch,066h,066h
  3445.         db      066h,06Ch,0F8h,000h
  3446.         db      0FEh,062h,068h,078h
  3447.         db      068h,062h,0FEh,000h
  3448.         db      0FEh,062h,068h,078h
  3449.         db      068h,060h,0F0h,000h
  3450.         db      03Ch,066h,0C0h,0C0h
  3451.         db      0CEh,066h,03Eh,000h
  3452.  
  3453.         db      0CCh,0CCh,0CCh,0FCh
  3454.         db      0CCh,0CCh,0CCh,000h
  3455.         db      078h,030h,030h,030h
  3456.         db      030h,030h,078h,000h
  3457.         db      01Eh,00Ch,00Ch,00Ch
  3458.         db      0CCh,0CCh,078h,000h
  3459.         db      0E6h,066h,06Ch,078h
  3460.         db      06Ch,066h,0E6h,000h
  3461.  
  3462.         db      0F0h,060h,060h,060h
  3463.         db      062h,066h,0FEh,000h
  3464.         db      0C6h,0EEh,0FEh,0FEh
  3465.         db      0D6h,0C6h,0C6h,000h
  3466.         db      0C6h,0E6h,0F6h,0DEh
  3467.         db      0CEh,0C6h,0C6h,000h
  3468.         db      038h,06Ch,0C6h,0C6h
  3469.         db      0C6h,06Ch,038h,000h
  3470.  
  3471.         db      0FCh,066h,066h,07Ch
  3472.         db      060h,060h,0F0h,000h
  3473.         db      078h,0CCh,0CCh,0CCh
  3474.         db      0DCh,078h,01Ch,000h
  3475.         db      0FCh,066h,066h,07Ch
  3476.         db      06Ch,066h,0E6h,000h
  3477.         db      078h,0CCh,0E0h,070h
  3478.         db      01Ch,0CCh,078h,000h
  3479.  
  3480.         db      0FCh,0B4h,030h,030h
  3481.         db      030h,030h,078h,000h
  3482.         db      0CCh,0CCh,0CCh,0CCh
  3483.         db      0CCh,0CCh,0FCh,000h
  3484.         db      0CCh,0CCh,0CCh,0CCh
  3485.         db      0CCH,078h,030h,000h
  3486.         db      0C6h,0C6h,0C6h,0D6h
  3487.         db      0FEh,0EEh,0C6h,000h
  3488.  
  3489.         db      0C6h,0C6h,06Ch,038h
  3490.         db      038h,06Ch,0C6h,000h
  3491.         db      0CCh,0CCh,0CCh,078h
  3492.         db      030h,030h,078h,000h
  3493.         db      0FEh,0C6h,08Ch,018h
  3494.         db      032h,066h,0FEh,000h
  3495.         db      078h,060h,060h,060h
  3496.         db      060h,060h,078h,000h
  3497.  
  3498.         db      0C0h,060h,030h,018h
  3499.         db      00Ch,006h,002h,000h
  3500.         db      078h,018h,018h,018h
  3501.         db      018h,018h,078h,000h
  3502.         db      010h,038h,06Ch,0C6h
  3503.         db      000h,000h,000h,000h
  3504.         db      000h,000h,000h,000h
  3505.         db      000h,000h,000h,0FFh
  3506.  
  3507.         db      030h,030h,018h,000h
  3508.         db      000h,000h,000h,000h
  3509.         db      000h,000h,078h,00Ch
  3510.         db      07Ch,0CCh,076h,000h
  3511.         db      0E0h,060h,060h,07Ch
  3512.         db      066h,066h,0DCh,000h
  3513.         db      000h,000h,078h,0CCh
  3514.         db      0C0h,0CCh,078h,000h
  3515.  
  3516.         db      01Ch,00Ch,00Ch,07Ch
  3517.         db      0CCh,0CCh,076h,000h
  3518.         db      000h,000h,078h,0CCh
  3519.         db      0FCh,0C0h,078h,000h
  3520.         db      038h,06Ch,060h,0F0h
  3521.         db      060h,060h,0F0h,000h
  3522.         db      000h,000h,076h,0CCh
  3523.         db      0CCh,07Ch,00Ch,0F8h
  3524.  
  3525.         db      0E0h,060h,06Ch,076h
  3526.         db      066h,066h,0E6h,000h
  3527.         db      030h,000h,070h,030h
  3528.         db      030h,030h,078h,000h
  3529.         db      00Ch,000h,00Ch,00Ch
  3530.         db      00Ch,0CCh,0CCh,078h
  3531.         db      0E0h,060h,066h,06Ch
  3532.         db      078h,06Ch,0E6h,000h
  3533.  
  3534.         db      070h,030h,030h,030h
  3535.         db      030h,030h,078h,000h
  3536.         db      000h,000h,0CCh,0FEh
  3537.         db      0FEh,0D6h,0C6h,000h
  3538.         db      000h,000h,0F8h,0CCh
  3539.         db      0CCh,0CCh,0CCh,000h
  3540.         db      000h,000h,078h,0CCh
  3541.         db      0CCh,0CCh,078h,000h
  3542.  
  3543.         db      000h,000h,0DCh,066h
  3544.         db      066h,07Ch,060h,0F0h
  3545.         db      000h,000h,076h,0CCh
  3546.         db      0CCh,07Ch,00Ch,01Eh
  3547.         db      000h,000h,0DCh,076h
  3548.         db      066h,060h,0F0h,000h
  3549.         db      000h,000h,07Ch,0C0h
  3550.         db      078h,00Ch,0F8h,000h
  3551.  
  3552.         db      010h,030h,07Ch,030h
  3553.         db      030h,034h,018h,000h
  3554.         db      000h,000h,0CCh,0CCh
  3555.         db      0CCh,0CCh,076h,000h
  3556.         db      000h,000h,0CCh,0CCh
  3557.         db      0CCh,078h,030h,000h
  3558.         db      000h,000h,0C6h,0D6h
  3559.         db      0FEh,0FEh,06Ch,000h
  3560.  
  3561.         db      000h,000h,0C6h,06Ch
  3562.         db      038h,06Ch,0C6h,000h
  3563.         db      000h,000h,0CCh,0CCh
  3564.         db      0CCh,07Ch,00Ch,0F8h
  3565.         db      000h,000h,0FCh,098h
  3566.         db      030h,064h,0FCh,000h
  3567.         db      01Ch,030h,030h,0E0h
  3568.         db      030h,030h,01Ch,000h
  3569.  
  3570.         db      018h,018h,018h,000h
  3571.         db      018h,018h,018h,000h
  3572.         db      0E0h,030h,030h,01Ch
  3573.         db      030h,030h,0E0h,000h
  3574.         db      076h,0DCh,000h,000h
  3575.         db      000h,000h,000h,000h
  3576.         db      000h,010h,038h,06Ch
  3577.         db      0C6h,0C6h,0FEh,000h
  3578.  
  3579.         ENTRY   0FE6Eh                          ; IBM entry, time_of_day clock
  3580.  
  3581. INT_1A: STI                                     ; User time_of_day bios service
  3582.         PUSH    DS
  3583.         PUSH    AX
  3584.         MOV     AX,40h
  3585.         MOV     DS,AX
  3586.         POP     AX                              ; Get request type
  3587.         CLI                                     ;  ...freeze clock
  3588.         OR      AH,AH
  3589.         JZ      TD_01                           ; Read time, AH=0
  3590.         DEC     AH
  3591.         JNZ     TD_02                           ;  ...invalid request
  3592.         MOV     DS:6Ch,DX                       ; Set time,  AH=1
  3593.         MOV     DS:6Eh,CX                       ;  ...set time hi
  3594.         MOV     Byte ptr DS:70h,0               ;  ...not a new day
  3595.         JMP     short   TD_02
  3596.  
  3597. TD_01:  MOV     CX,DS:6Eh                       ; Read lo order time
  3598.         MOV     DX,DS:6Ch                       ;  ... hi order time
  3599.         CALL    TD_03                           ; Read resets overflow
  3600.  
  3601. TD_02:  STI                                     ; Unfreeze clock
  3602.         POP     DS
  3603.         IRET
  3604.  
  3605. TD_03:  MOV     AL,DS:70h                       ; Zero the overflow and return
  3606.         XOR     DS:70h,AL                       ;  ...previous status in flags
  3607.         RET
  3608.  
  3609.         ENTRY   0FEA5h                          ; IBM entry, hardware clock
  3610.  
  3611. INT_8:  STI                                     ; Routine services clock tick
  3612.         PUSH    DS
  3613.         PUSH    DX
  3614.         PUSH    AX
  3615.         MOV     AX,40h
  3616.         MOV     DS,AX
  3617.         DEC     Byte ptr DS:40h                 ; Decrement motor count
  3618.         JNZ     TI_01                           ;  ...not time to shut off
  3619.         AND     Byte ptr DS:3Fh,11110000b       ; Else show motor off
  3620.         MOV     AL,0Ch                          ;  ...send motor off
  3621.         MOV     DX,3F2h                         ;  ...to the floppy
  3622.         OUT     DX,AL                           ;  ...disk controller
  3623.  
  3624. TI_01:  INC     Word ptr DS:6Ch                 ; Bump lo order time of day
  3625.         JNZ     TI_02                           ;  ...no carry
  3626.         INC     Word ptr DS:6Eh                 ; Bump hi order time of day
  3627.  
  3628. TI_02:  CMP     Word ptr DS:6Eh,18h             ; Is it midnight yet?
  3629.         JNZ     TI_03                           ;  ...no
  3630.         CMP     Word ptr DS:6Ch,0B0h            ; Possibly, check lo order
  3631.         JNZ     TI_03                           ;  ...not midnight
  3632.         MOV     Word ptr DS:6Eh,0               ; Midnight, reset hi order
  3633.         MOV     Word ptr DS:6Ch,0               ;  ...lo order ticks
  3634.         MOV     Byte ptr DS:70h,1               ; Show new day since last read
  3635.  
  3636. TI_03:  INT     1Ch                             ; Execute user clock service
  3637.         MOV     AL,20h                          ;  ...send end_of_interrupt
  3638.         OUT     20h,AL                          ;  ...to 8259 interrupt chip
  3639.         POP     AX
  3640.         POP     DX
  3641.         POP     DS
  3642.         IRET
  3643.  
  3644.         ENTRY   0FEF3h                          ; IBM entry, time_of_day clock
  3645.  
  3646. VECTORS dw      int_8                           ; Timer tick
  3647.         dw      int_9                           ; Key attention
  3648.         dw      IGNORE                          ; Reserved
  3649.         dw      IGNORE                          ; Reserved for COM2 serial i/o
  3650.         dw      IGNORE                          ; Reserved for COM1 serial i/o
  3651.         dw      IGNORE                          ; Reserved for hard disk attn.
  3652.         dw      int_e                           ; Floppy disk attention
  3653.         dw      IGNORE                          ; Reserved for parallel printer
  3654.         dw      int_10                          ; Video bios services
  3655.         dw      int_11                          ; Equipment present
  3656.         dw      int_12                          ; Memories  present
  3657.         dw      int_13                          ; Disk bios services
  3658.         dw      int_14                          ; Serial com. services
  3659.         dw      int_15                          ; Cassette bios services
  3660.         dw      int_16                          ; Keyboard bios services
  3661.         dw      int_17                          ; Parallel printer services
  3662.         dw      IGNORE                          ; rom Basic (setup later)
  3663.         dw      int_19                          ; Bootstrap
  3664.         dw      int_1a                          ; Timer bios services
  3665.         dw      DUMMY                           ; Keyboard break user service
  3666.         dw      DUMMY                           ; System tick user service
  3667.         dw      int_1d                          ; Video  parameter table
  3668.         dw      int_1e                          ; Disk   parameter table
  3669.         dw      ?                               ; Graphic charactr table ptr
  3670.  
  3671.         ENTRY   0FF23h                          ; IBM entry, nonsense interrupt
  3672.  
  3673. IGNORE: PUSH    DS                              ; Unexpected interrupts go here
  3674.         PUSH    DX
  3675.         PUSH    AX
  3676.         MOV     AX,40h
  3677.         MOV     DS,AX
  3678.         MOV     AL,0Bh                          ; What IRQ caused this?
  3679.         OUT     20h,AL
  3680.         NOP
  3681.         IN      AL,20h                          ;  ...(read IRQ level)
  3682.         MOV     AH,AL
  3683.         OR      AL,AL
  3684.         JNZ     DU_1
  3685.         MOV     AL,0FFh                         ; Not hardware, say 0FFh IRQ
  3686.         JMP     short   DU_2
  3687.  
  3688. DU_1:   IN      AL,21h                          ; Clear the IRQ
  3689.         OR      AL,AH
  3690.         OUT     21h,AL
  3691.         MOV     AL,20h                          ; Send end_of_interrupt code
  3692.         OUT     20h,AL                          ;  ...to 8259 interrupt chip
  3693.  
  3694. DU_2:   MOV     DS:6Bh,AH                       ; Save last nonsense interrupt
  3695.         POP     AX
  3696.         POP     DX
  3697.         POP     DS
  3698.         IRET
  3699.  
  3700.         ENTRY   0FF53h                          ; IBM entry, dummy interrupts
  3701.  
  3702. ;INT_1B:                                        ; Keyboard break user service
  3703. ;INT_1C:                                        ; Clock    tick  user service
  3704. DUMMY:  IRET
  3705.  
  3706.         ENTRY   0FF54h                          ; IBM entry, print screen
  3707.  
  3708. INT_5:  STI                                     ; Print screen service
  3709.         PUSH    DS
  3710.         PUSH    AX
  3711.         PUSH    BX
  3712.         PUSH    CX
  3713.         PUSH    DX
  3714.         MOV     AX,40h
  3715.         MOV     DS,AX
  3716.         CMP     Byte ptr DS:100h,1              ; Print screen in progress?
  3717.         JZ      PS_5                            ;  ...yes, ignore
  3718.         MOV     Byte ptr DS:100h,1              ; Flag print screen in progress
  3719.         CALL    P_CRLF                          ;  ...begin new line
  3720.         MOV     AH,0Fh
  3721.         INT     10h                             ; Get current video state
  3722.         PUSH    AX                              ;  ...save it
  3723.         MOV     AH,3
  3724.         INT     10h                             ; Read cursor position
  3725.         POP     AX                              ;  ...retrieve video state
  3726.         PUSH    DX                              ;  ...save cursor position
  3727.         MOV     CH,19h                          ; Do 25 rows
  3728.         MOV     CL,AH                           ;  ...columns in current mode
  3729.         XOR     DX,DX                           ; Start printing from (0,0)
  3730.  
  3731. PS_1:   MOV     AH,2                            ; Set cursor to position
  3732.         INT     10h
  3733.         MOV     AH,8                            ;  ...and read character
  3734.         INT     10h
  3735.         OR      AL,AL                           ; Nulls are special case
  3736.         JNZ     PS_2
  3737.         MOV     AL,' '                          ;  ...convert to spaces
  3738.  
  3739. PS_2:   PUSH    DX
  3740.         XOR     DX,DX
  3741.         MOV     AH,DL                           ; Function=Print character
  3742.         INT     17h
  3743.         POP     DX
  3744.         TEST    AH,00100101b                    ; Successful print
  3745.         JZ      PS_3
  3746.         MOV     Byte ptr DS:100h,0FFh           ; No, error in Print Screen
  3747.         JMP     short   PS_4
  3748.  
  3749. PS_3:   INC     DL                              ; Increment column count
  3750.         CMP     CL,DL
  3751.         JNZ     PS_1                            ;  ...in range, continue
  3752.         MOV     DL,0
  3753.         CALL    P_CRLF                          ; Else print new line
  3754.         INC     DH                              ;  ...add another row
  3755.         CMP     DH,CH                           ; Done all 25 rows?
  3756.         JNZ     PS_1                            ;  ...no, continue
  3757.         MOV     Byte ptr DS:100h,0              ; Show done Print Screen OK
  3758.  
  3759. PS_4:   POP     DX                              ; Get saved cursor position
  3760.         MOV     AH,2
  3761.         INT     10h                             ;  ...restore it
  3762.  
  3763. PS_5:   POP     DX
  3764.         POP     CX
  3765.         POP     BX
  3766.         POP     AX
  3767.         POP     DS
  3768.         IRET
  3769.  
  3770.         ENTRY   0FFCBh                          ; IBM entry, display CR, LF
  3771.  
  3772. P_CRLF: PUSH    DX                              ; Print CR, LF, on line printer
  3773.         XOR     DX,DX
  3774.         MOV     AH,DL                           ; Function=print
  3775.         MOV     AL,LF                           ;     LF
  3776.         INT     17h
  3777.         MOV     AH,0
  3778.         MOV     AL,CR                           ;     CR
  3779.         INT     17h
  3780.         POP     DX
  3781.         RET
  3782.  
  3783. ;******************************************************************************
  3784.         ENTRY   0FFF0h                          ; Hardware power reset entry  *
  3785.         PUBLIC  POWER                           ;  ...ic "8088" or "V20"      *
  3786. POWER:  JMPF    0F000h,COLD                     ;  ...begins here on power up *
  3787. ;******************************************************************************
  3788.  
  3789.         ENTRY   0FFF5h                          ; Release date, Yankee style
  3790.         db      "08/23/87"                      ;  ...MM/DD/YY (not logical)
  3791.  
  3792.         ENTRY   0FFFEh
  3793.         db      0FEh                            ; Computer type (XT)
  3794. ;       db      ?                               ; Checksum byte
  3795. code    ENDS
  3796. ;
  3797. END
  3798.